Merge pull request #2449 from mrry/branch_122885116

Branch 122885116
This commit is contained in:
Derek Murray 2016-05-22 11:09:00 -07:00
commit 67993f9674
128 changed files with 5451 additions and 1244 deletions

View File

@ -77,7 +77,7 @@ filegroup(
"//tensorflow/contrib/ctc:all_files",
"//tensorflow/contrib/distributions:all_files",
"//tensorflow/contrib/ffmpeg:all_files",
"//tensorflow/contrib/ffmpeg/kernels:all_files",
"//tensorflow/contrib/ffmpeg/default:all_files",
"//tensorflow/contrib/framework:all_files",
"//tensorflow/contrib/layers:all_files",
"//tensorflow/contrib/layers/kernels:all_files",

View File

@ -80,6 +80,49 @@ class ExponentialTest(tf.test.TestCase):
self.assertEqual(exponential.entropy().get_shape(), (3,))
self.assertAllClose(exponential.entropy().eval(), expected_entropy)
def testExponentialSample(self):
with self.test_session():
lam = tf.constant([3.0, 4.0])
lam_v = [3.0, 4.0]
n = tf.constant(100000)
exponential = tf.contrib.distributions.Exponential(lam=lam)
samples = exponential.sample(n, seed=137)
sample_values = samples.eval()
self.assertEqual(sample_values.shape, (100000, 2))
self.assertFalse(np.any(sample_values < 0.0))
for i in range(2):
self.assertLess(
stats.kstest(
sample_values[:, i], stats.expon(scale=1.0/lam_v[i]).cdf)[0],
0.01)
def testExponentialSampleMultiDimensional(self):
with self.test_session():
batch_size = 2
lam_v = [3.0, 22.0]
lam = tf.constant([lam_v] * batch_size)
exponential = tf.contrib.distributions.Exponential(lam=lam)
n_v = 100000
n = tf.constant(n_v)
samples = exponential.sample(n, seed=138)
self.assertEqual(samples.get_shape(), (n_v, batch_size, 2))
sample_values = samples.eval()
self.assertFalse(np.any(sample_values < 0.0))
for i in range(2):
self.assertLess(
stats.kstest(
sample_values[:, 0, i], stats.expon(scale=1.0/lam_v[i]).cdf)[0],
0.01)
self.assertLess(
stats.kstest(
sample_values[:, 1, i], stats.expon(scale=1.0/lam_v[i]).cdf)[0],
0.01)
if __name__ == '__main__':
tf.test.main()

View File

@ -200,15 +200,26 @@ class ContinuousDistribution(BaseDistribution):
"""Base class for continuous probability distributions.
`ContinuousDistribution` defines the API for the likelihood functions `pdf`
and `log_pdf` of continuous probability distributions.
and `log_pdf` of continuous probability distributions, and a property
`is_reparameterized` (returning `True` or `False`) which describes
whether the samples of this distribution are calculated in a differentiable
way from a non-parameterized distribution. For example, the `Normal`
distribution with parameters `mu` and `sigma` is reparameterized as
Subclasses must override both `pdf` and `log_pdf` but one can call this base
class's implementation.
```Normal(mu, sigma) = sigma * Normal(0, 1) + mu```
Subclasses must override `pdf` and `log_pdf` but one can call this base
class's implementation. They must also override the `is_reparameterized`
property.
See `BaseDistribution` for more information on the API for probability
distributions.
"""
@abc.abstractproperty
def is_reparameterized(self):
pass
@abc.abstractmethod
def pdf(self, value, name="pdf"):
"""Probability density function."""

View File

@ -20,7 +20,11 @@ from __future__ import print_function
from tensorflow.contrib.distributions.python.ops import gamma
from tensorflow.python.framework import ops
from tensorflow.python.framework import tensor_shape
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 random_ops
class Exponential(gamma.Gamma):
@ -45,3 +49,35 @@ class Exponential(gamma.Gamma):
@property
def lam(self):
return self._lam
@property
def is_reparameterized(self):
# While the Gamma distribution is not reparameterizeable, the
# exponential distribution is.
return True
def sample(self, n, seed=None, name=None):
"""Sample `n` observations from the Exponential Distributions.
Args:
n: `Scalar`, type int32, the number of observations to sample.
seed: Python integer, the random seed.
name: The name to give this op.
Returns:
samples: `[n, ...]`, a `Tensor` of `n` samples for each
of the distributions determined by the hyperparameters.
"""
broadcast_shape = self._lam.get_shape()
with ops.op_scope([self.lam, n], name, "ExponentialSample"):
shape = array_ops.concat(
0, [array_ops.pack([n]), array_ops.shape(self._lam)])
sampled = random_ops.random_uniform(
shape, maxval=math_ops.cast(1.0, dtype=self.dtype),
dtype=self.dtype)
n_val = tensor_util.constant_value(n)
final_shape = tensor_shape.vector(n_val).concatenate(broadcast_shape)
sampled.set_shape(final_shape)
return -math_ops.log(sampled) / self._lam

View File

@ -206,3 +206,7 @@ class Gamma(ContinuousDistribution):
beta = self._beta
return (alpha - math_ops.log(beta) + math_ops.lgamma(alpha) +
(1 - alpha) * math_ops.digamma(alpha))
@property
def is_reparameterized(self):
return False

View File

@ -229,3 +229,7 @@ class Gaussian(object):
sampled.set_shape(final_shape)
return sampled * self._sigma + self._mu
@property
def is_reparameterized(self):
return True

View File

@ -454,3 +454,7 @@ class MultivariateNormal(object):
samples.set_shape(final_shape)
return samples
@property
def is_reparameterized(self):
return True

View File

@ -277,6 +277,10 @@ class StudentT(ContinuousDistribution):
return samples * self._sigma + self._mu
@property
def is_reparameterized(self):
return True
def _ones(self):
return array_ops.ones_like(self._df + self._mu + self._sigma)

View File

@ -231,6 +231,10 @@ class Uniform(ContinuousDistribution):
"""`b - a`."""
return self.b - self.a
@property
def is_reparameterized(self):
return True
# TODO(rsepassi): Find a more efficient way of doing the broadcasting in_ones
# and _zeros.
def _ones(self):

View File

@ -24,7 +24,7 @@ cc_library(
linkstatic = 1,
visibility = ["//visibility:private"],
deps = [
"//tensorflow/contrib/ffmpeg/kernels:ffmpeg_lib",
"//tensorflow/contrib/ffmpeg/default:ffmpeg_lib",
"//tensorflow/core:framework_headers_lib",
"//third_party/eigen3",
],
@ -38,7 +38,7 @@ cc_library(
linkstatic = 1,
visibility = ["//visibility:private"],
deps = [
"//tensorflow/contrib/ffmpeg/kernels:ffmpeg_lib",
"//tensorflow/contrib/ffmpeg/default:ffmpeg_lib",
"//tensorflow/core:framework_headers_lib",
"//third_party/eigen3",
],

View File

@ -18,7 +18,7 @@
#include <cstdio>
#include <set>
#include "tensorflow/contrib/ffmpeg/kernels/ffmpeg_lib.h"
#include "tensorflow/contrib/ffmpeg/default/ffmpeg_lib.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/lib/io/path.h"

View File

@ -25,7 +25,6 @@ cc_test(
"--should_ffmpeg_be_installed=true",
],
data = [
":testdata/test_sound1.mp3",
"//tensorflow/contrib/ffmpeg:test_data",
],
tags = [
@ -46,9 +45,6 @@ cc_test(
args = [
"--should_ffmpeg_be_installed=false",
],
data = [
":testdata/test_sound1.mp3",
],
tags = [
"local",
"manual",

View File

@ -13,15 +13,13 @@
// limitations under the License.
// =============================================================================
#include "tensorflow/contrib/ffmpeg/kernels/ffmpeg_lib.h"
#include "tensorflow/contrib/ffmpeg/default/ffmpeg_lib.h"
#include <errno.h>
#include <stdlib.h>
#include <string>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <tuple>
#include <unistd.h>
#include <vector>

View File

@ -13,8 +13,8 @@
// limitations under the License.
// =============================================================================
#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_KERNELS_FFMPEG_LIB_H_
#define THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_KERNELS_FFMPEG_LIB_H_
#ifndef THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_DEFAULT_FFMPEG_LIB_H_
#define THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_DEFAULT_FFMPEG_LIB_H_
#include <string>
@ -47,4 +47,4 @@ Status CreateAudioFile(const string& audio_format_id, int32 samples_per_second,
} // namespace ffmpeg
} // namespace tensorflow
#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_KERNELS_FFMPEG_LIB_H_
#endif // THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_DEFAULT_FFMPEG_LIB_H_

View File

@ -13,7 +13,7 @@
// limitations under the License.
// =============================================================================
#include "tensorflow/contrib/ffmpeg/kernels/ffmpeg_lib.h"
#include "tensorflow/contrib/ffmpeg/default/ffmpeg_lib.h"
#include <stdlib.h>
#include <vector>
@ -35,7 +35,7 @@ namespace {
const char kTestWavFilename[] =
"contrib/ffmpeg/testdata/mono_10khz.wav";
const char kTestMp3Filename[] =
"contrib/ffmpeg/kernels/testdata/test_sound1.mp3";
"contrib/ffmpeg/testdata/test_sound1.mp3";
// Set to true via a command line flag iff the test is expected to have FFmpeg
// installed.

View File

@ -15,7 +15,7 @@
#include <limits>
#include "tensorflow/contrib/ffmpeg/kernels/ffmpeg_lib.h"
#include "tensorflow/contrib/ffmpeg/default/ffmpeg_lib.h"
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"

View File

@ -117,8 +117,9 @@ def summarize_tensor(tensor, tag=None):
Returns:
The summary op created or None for string tensors.
"""
# Skips string tensors.
if tensor.dtype.is_compatible_with(dtypes.string):
# Skips string tensors and boolean tensors (not handled by the summaries).
if (tensor.dtype.is_compatible_with(dtypes.string) or
tensor.dtype.base_dtype == dtypes.bool):
return None
if tensor.get_shape().ndims == 0:

View File

@ -61,6 +61,20 @@ py_test(
],
)
py_test(
name = "test_feeding_queue_runner",
size = "small",
srcs = [
"python/learn/tests/dataframe/test_feeding_queue_runner.py",
],
srcs_version = "PY2AND3",
deps = [
":learn",
"//tensorflow:tensorflow_py",
"//tensorflow/python:framework_test_lib",
],
)
py_test(
name = "test_early_stopping",
size = "medium",
@ -108,6 +122,42 @@ py_test(
],
)
py_test(
name = "dnn_linear_combined_test",
size = "small",
srcs = ["python/learn/estimators/dnn_linear_combined_test.py"],
srcs_version = "PY2AND3",
deps = [
":learn",
"//tensorflow:tensorflow_py",
"//tensorflow/python:framework_test_lib",
],
)
py_test(
name = "dnn_test",
size = "small",
srcs = ["python/learn/estimators/dnn_test.py"],
srcs_version = "PY2AND3",
deps = [
":learn",
"//tensorflow:tensorflow_py",
"//tensorflow/python:framework_test_lib",
],
)
py_test(
name = "linear_test",
size = "small",
srcs = ["python/learn/estimators/linear_test.py"],
srcs_version = "PY2AND3",
deps = [
":learn",
"//tensorflow:tensorflow_py",
"//tensorflow/python:framework_test_lib",
],
)
py_test(
name = "test_grid_search",
size = "small",

View File

@ -20,6 +20,9 @@ from __future__ import print_function
import numpy as np
from tensorflow.contrib.learn.python.learn import datasets
from tensorflow.contrib.learn.python.learn import estimators
from tensorflow.contrib.learn.python.learn import graph_actions
from tensorflow.contrib.learn.python.learn import io
from tensorflow.contrib.learn.python.learn import models
from tensorflow.contrib.learn.python.learn import monitors
from tensorflow.contrib.learn.python.learn import ops

View File

@ -0,0 +1,144 @@
# Copyright 2016 Google Inc. 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 enqueuing data from arrays and pandas `DataFrame`s."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
import tensorflow.contrib.learn.python.learn.dataframe.queues.feeding_queue_runner as fqr
# pylint: disable=g-import-not-at-top
try:
import pandas as pd
HAS_PANDAS = True
except ImportError:
HAS_PANDAS = False
class _ArrayFeedFn(object):
"""Creates feed dictionaries from numpy arrays."""
def __init__(self, placeholders, array):
if len(placeholders) != 2:
raise ValueError("_array_feed_fn expects 2 placeholders; got {}.".format(
len(placeholders)))
self._placeholders = placeholders
self._array = array
self._reset()
def _reset(self):
self._row_iterator = enumerate(self._array)
def __call__(self):
try:
index, row = next(self._row_iterator)
except StopIteration:
self._reset()
index, row = next(self._row_iterator)
return {self._placeholders[0]: index, self._placeholders[1]: row}
class _PandasFeedFn(object):
"""Creates feed dictionaries from pandas `DataFrames`."""
def __init__(self, placeholders, dataframe):
if len(placeholders) != len(dataframe.columns) + 1:
raise ValueError("Expected {} placeholders; got {}.".format(
len(dataframe.columns), len(placeholders)))
self._index_placeholder = placeholders[0]
self._row_placeholders = placeholders[1:]
self._dataframe = dataframe
self._reset()
def _reset(self):
self._row_iterator = self._dataframe.iterrows()
def __call__(self):
try:
index, row = next(self._row_iterator)
except StopIteration:
self._reset()
index, row = next(self._row_iterator)
feed_dict = dict(zip(self._row_placeholders, row))
feed_dict[self._index_placeholder] = index
return feed_dict
def enqueue_data(data,
capacity,
shuffle=False,
min_after_dequeue=None,
seed=None):
"""Creates a queue filled from a numpy array or pandas `DataFrame`.
Returns a queue filled with the rows of the given array or `DataFrame`. In
the case of a pandas `DataFrame`, the first enqueued `Tensor` corresponds to
the index of the `DataFrame`. For numpy arrays, the first enqueued `Tensor`
contains the row number.
Args:
data: a numpy `ndarray or` pandas `DataFrame` that will be read into the
queue.
capacity: the capacity of the queue.
shuffle: whether or not to shuffle the rows of the array.
min_after_dequeue: minimum number of elements that can remain in the queue
after a dequeue operation. Only used when `shuffle` is true. If not set,
defaults to `capacity` / 4.
seed: used to seed RandomShuffleQueue. Only used when `shuffle` is True.
Returns:
A queue filled with the rows of the given array or `DataFrame`.
Raises:
TypeError: `data` is not a Pandas `DataFrame` or a numpy `ndarray`.
"""
# TODO(jamieas): create multithreaded version of enqueue_data.
if isinstance(data, np.ndarray):
dtypes = [tf.int64, tf.as_dtype(data.dtype)]
shapes = [(), data.shape[1:]]
get_feed_fn = _ArrayFeedFn
elif HAS_PANDAS and isinstance(data, pd.DataFrame):
dtypes = [tf.as_dtype(dt) for dt in [data.index.dtype] + list(data.dtypes)]
shapes = [() for _ in dtypes]
get_feed_fn = _PandasFeedFn
else:
raise TypeError(
"data must be either a numpy array or pandas DataFrame if pandas is "
"installed; got {}".format(
type(data).__name__))
placeholders = [tf.placeholder(*type_and_shape)
for type_and_shape in zip(dtypes, shapes)]
if shuffle:
min_after_dequeue = (capacity / 4 if min_after_dequeue is None else
min_after_dequeue)
queue = tf.RandomShuffleQueue(capacity,
min_after_dequeue,
dtypes=dtypes,
shapes=shapes,
seed=seed)
else:
queue = tf.FIFOQueue(capacity, dtypes=dtypes, shapes=shapes)
enqueue_op = queue.enqueue(placeholders)
feed_fn = get_feed_fn(placeholders, data)
queue_runner = fqr.FeedingQueueRunner(queue=queue,
enqueue_ops=[enqueue_op],
feed_fn=feed_fn)
tf.train.add_queue_runner(queue_runner)
return queue

View File

@ -0,0 +1,105 @@
# Copyright 2016 Google Inc. 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.
# ==============================================================================
"""A `QueueRunner` that takes a feed function as an argument."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from tensorflow.python.framework import errors
from tensorflow.python.platform import tf_logging as logging
from tensorflow.python.training import queue_runner as qr
class FeedingQueueRunner(qr.QueueRunner):
"""A queue runner that allows the feeding of values such as numpy arrays."""
def __init__(self, queue=None, enqueue_ops=None, close_op=None,
cancel_op=None, feed_fn=None):
"""Initialize the queue runner.
For further documentation, see `queue_runner.py`. Note that
`FeedingQueueRunner` does not support construction from protobuffer nor
serialization to protobuffer.
Args:
queue: A `Queue`.
enqueue_ops: List of enqueue ops to run in threads later.
close_op: Op to close the queue. Pending enqueue ops are preserved.
cancel_op: Op to close the queue and cancel pending enqueue ops.
feed_fn: a function that returns a dictionary mapping fed `Tensor`s to
values.
"""
super(FeedingQueueRunner, self).__init__(queue, enqueue_ops, close_op,
cancel_op)
self._feed_fn = feed_fn
# pylint: disable=broad-except
def _run(self, sess, enqueue_op, coord=None):
"""Execute the enqueue op in a loop, close the queue in case of error.
Args:
sess: A `Session`.
enqueue_op: The `Operation` to run.
coord: Optional `Coordinator` object for reporting errors and checking
for stop conditions.
"""
# TODO(jamieas): Reduce code duplication with `QueueRunner`.
decremented = False
try:
while True:
if coord and coord.should_stop():
break
try:
feed_dict = None if self._feed_fn is None else self._feed_fn()
sess.run(enqueue_op, feed_dict=feed_dict)
except errors.OutOfRangeError:
# This exception indicates that a queue was closed.
with self._lock:
self._runs -= 1
decremented = True
if self._runs == 0:
try:
sess.run(self._close_op)
except Exception as e:
# Intentionally ignore errors from close_op.
logging.vlog(1, "Ignored exception: %s", str(e))
return
except Exception as e:
# This catches all other exceptions.
if coord:
coord.request_stop(e)
else:
logging.error("Exception in QueueRunner: %s", str(e))
with self._lock:
self._exceptions_raised.append(e)
raise
finally:
# Make sure we account for all terminations: normal or errors.
if not decremented:
with self._lock:
self._runs -= 1
def _init_from_proto(self, queue_runner_def):
raise NotImplementedError(
"{} does not support initialization from proto.".format(type(
self).__name__))
def to_proto(self):
raise NotImplementedError(
"{} does not support serialization to proto.".format(type(
self).__name__))

View File

@ -18,11 +18,17 @@ from __future__ import print_function
from tensorflow.contrib.learn.python.learn.estimators.autoencoder import TensorFlowDNNAutoencoder
from tensorflow.contrib.learn.python.learn.estimators.base import TensorFlowEstimator, TensorFlowBaseTransformer
from tensorflow.contrib.learn.python.learn.estimators.dnn import DNNClassifier
from tensorflow.contrib.learn.python.learn.estimators.dnn import DNNRegressor
from tensorflow.contrib.learn.python.learn.estimators.dnn import TensorFlowDNNClassifier
from tensorflow.contrib.learn.python.learn.estimators.dnn import TensorFlowDNNRegressor
from tensorflow.contrib.learn.python.learn.estimators.dnn_linear_combined import DNNLinearCombinedClassifier
from tensorflow.contrib.learn.python.learn.estimators.dnn_linear_combined import DNNLinearCombinedRegressor
from tensorflow.contrib.learn.python.learn.estimators.estimator import BaseEstimator
from tensorflow.contrib.learn.python.learn.estimators.estimator import Estimator
from tensorflow.contrib.learn.python.learn.estimators.estimator import ModeKeys
from tensorflow.contrib.learn.python.learn.estimators.linear import LinearClassifier
from tensorflow.contrib.learn.python.learn.estimators.linear import LinearRegressor
from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowClassifier
from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowLinearClassifier
from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowLinearRegressor

View File

@ -45,12 +45,13 @@ from tensorflow.python.ops import variable_scope as vs
from tensorflow.python.training import training as train
from tensorflow.contrib.layers import optimizers
from tensorflow.contrib.learn.python.learn import trainer
from tensorflow.contrib.learn.python.learn.io.data_feeder import setup_train_data_feeder
from tensorflow.contrib.learn.python.learn.io.data_feeder import setup_predict_data_feeder
from tensorflow.contrib.learn.python.learn.ops.dropout_ops import DROPOUTS
from tensorflow.contrib.learn.python.learn import monitors
from tensorflow.contrib.learn.python.learn import monitors as monitors_lib
from tensorflow.contrib.learn.python.learn.utils import checkpoints
from tensorflow.contrib.learn.python.learn.estimators import estimator
from tensorflow.contrib.learn.python.learn.estimators import _sklearn
from tensorflow.contrib.learn.python.learn.estimators._sklearn import NotFittedError
from tensorflow.contrib.learn.python.learn.estimators.run_config import RunConfig
@ -63,7 +64,35 @@ def _write_with_backup(filename, content):
f.write(content)
class TensorFlowEstimator(_sklearn.BaseEstimator):
def _copy_dir(dir_in, dir_out):
gfile.MakeDirs(dir_out)
for name in gfile.ListDirectory(dir_in):
name_in = os.path.join(dir_in, name)
name_out = os.path.join(dir_out, name)
if gfile.IsDirectory(name_in):
gfile.MakeDirs(name_out)
_copy_dir(name_in, name_out)
else:
gfile.Copy(name_in, name_out, overwrite=True)
def _new_tf_model_fn(model_fn, class_weight):
"""Backward compatibility way of adding class weight and IS_TRAINING.
TODO(ipolosukhin): Remove this function after new layers are available.
Specifically:
* dropout and batch norm should work via update ops.
* class weights should be retrieved from weights column or hparams.
"""
def _model_fn(features, targets, mode):
ops.get_default_graph().add_to_collection('IS_TRAINING', mode == 'train')
if class_weight is not None:
constant_op.constant(class_weight, name='class_weight')
return model_fn(features, targets)
return _model_fn
class TensorFlowEstimator(estimator.Estimator):
"""Base class for all TensorFlow estimators.
Parameters:
@ -109,101 +138,21 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
continue_training=False,
config=None,
verbose=1):
self.model_fn = model_fn
super(TensorFlowEstimator, self).__init__(
model_fn=_new_tf_model_fn(model_fn, class_weight),
classification=n_classes > 1,
learning_rate=learning_rate,
optimizer=optimizer,
clip_gradients=clip_gradients,
config=config)
self.n_classes = n_classes
self.batch_size = batch_size
self.steps = steps
self.verbose = verbose
self.optimizer = optimizer
self.learning_rate = learning_rate
self.clip_gradients = clip_gradients
self.continue_training = continue_training
self._initialized = False
self.class_weight = class_weight
self._config = config
self._data_feeder = None
def _setup_training(self):
"""Sets up graph, model and trainer."""
# Create config if not given.
if self._config is None:
self._config = RunConfig(verbose=self.verbose)
# Create new graph.
self._graph = ops.Graph()
self._graph.add_to_collection('IS_TRAINING', True)
with self._graph.as_default():
random_seed.set_random_seed(self._config.tf_random_seed)
self._global_step = variables.Variable(0,
name='global_step',
trainable=False)
# Setting up inputs and outputs.
self._inp, self._out = self._data_feeder.input_builder()
# If class weights are provided, add them to the graph.
# Different loss functions can use this tensor by name.
if self.class_weight:
self._class_weight_node = constant_op.constant(self.class_weight,
name='class_weight')
# Add histograms for X and y if they are floats.
if self._data_feeder.input_dtype in (np.float32, np.float64):
logging_ops.histogram_summary('X', self._inp)
if self._data_feeder.output_dtype in (np.float32, np.float64)\
and self._out is not None:
logging_ops.histogram_summary('y', self._out)
# Create model's graph.
self._model_predictions, self._model_loss = self.model_fn(self._inp,
self._out)
# Set up a single operator to merge all the summaries
self._summaries = logging_ops.merge_all_summaries()
# Create trainer and augment graph with gradients and optimizer.
# Additionally creates initialization ops.
learning_rate = self.learning_rate
optimizer = self.optimizer
if callable(learning_rate):
learning_rate = learning_rate(self._global_step)
if callable(optimizer):
optimizer = optimizer(learning_rate)
self._train = optimizers.optimize_loss(self._model_loss,
self._global_step,
learning_rate=learning_rate,
optimizer=optimizer,
clip_gradients=self.clip_gradients)
# Update ops during training, e.g. batch_norm_ops
self._train = control_flow_ops.group(self._train, *
ops.get_collection('update_ops'))
# Get all initializers for all trainable variables.
self._initializers = variables.initialize_all_variables()
# Create model's saver capturing all the nodes created up until now.
self._saver = train.Saver(max_to_keep=self._config.keep_checkpoint_max,
keep_checkpoint_every_n_hours=
self._config.keep_checkpoint_every_n_hours)
# Enable monitor to create validation data dict with appropriate
# tf placeholders
self._monitor.create_val_feed_dict(self._inp, self._out)
# Create session to run model with.
self._session = session.Session(self._config.master,
config=self._config.tf_config)
# Run parameter initializers.
self._session.run(self._initializers)
def _setup_summary_writer(self, logdir):
"""Sets up summary writer to prepare for later optional visualization."""
self._summary_writer = train.SummaryWriter(
os.path.join(logdir,
datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')),
graph=self._session.graph)
def fit(self, X, y, monitor=None, logdir=None):
def fit(self, x, y, steps=None, monitors=None, logdir=None):
"""Builds a neural network model given provided `model_fn` and training
data X and y.
@ -214,63 +163,44 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
To restart learning, create new estimator.
Args:
X: matrix or tensor of shape [n_samples, n_features...]. Can be
x: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
y: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
monitor: Monitor object to print training progress and invoke early
stopping
steps: int, number of steps to train.
If None or 0, train for `self.steps`.
monitors: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
logdir: the directory to save the log file that can be used for
optional visualization.
Returns:
Returns self.
"""
# Sets up data feeder.
self._data_feeder = setup_train_data_feeder(X, y, self.n_classes,
self.batch_size)
if monitor is None:
self._monitor = monitors.default_monitor(verbose=self.verbose)
else:
self._monitor = monitor
if not self.continue_training or not self._initialized:
# Sets up model and trainer.
self._setup_training()
self._initialized = True
else:
self._data_feeder.set_placeholders(self._inp, self._out)
# Sets up summary writer for later optional visualization.
# Due to not able to setup _summary_writer in __init__ as it's not a
# parameter of the model, here we need to check if such variable exists
# and if it's None or not (in case it was setup in a previous run).
# It is initialized only in the case where it wasn't before and log dir
# is provided.
if logdir:
if (not hasattr(self, '_summary_writer') or
(hasattr(self, '_summary_writer') and self._summary_writer is None)):
self._setup_summary_writer(logdir)
else:
self._summary_writer = None
# Train model for given number of steps.
trainer.train(self._session,
self._train,
self._model_loss,
self._global_step,
self._data_feeder.get_feed_dict_fn(),
steps=self.steps,
monitor=self._monitor,
summary_writer=self._summary_writer,
summaries=self._summaries,
feed_params_fn=self._data_feeder.get_feed_params)
if logdir is not None:
self._model_dir = logdir
self._data_feeder = setup_train_data_feeder(
x, y, n_classes=self.n_classes, batch_size=self.batch_size)
self._train_model(input_fn=self._data_feeder.input_builder,
feed_fn=self._data_feeder.get_feed_dict_fn(),
steps=steps or self.steps,
monitors=monitors)
return self
def partial_fit(self, X, y):
def evaluate(self, x=None, y=None, input_fn=None, steps=None):
"""See base class."""
feed_fn = None
if x is not None:
eval_data_feeder = setup_train_data_feeder(
x, y, n_classes=self.n_classes, batch_size=self.batch_size, epochs=1)
input_fn, feed_fn = (eval_data_feeder.input_builder,
eval_data_feeder.get_feed_dict_fn())
return self._evaluate_model(
input_fn=input_fn, feed_fn=feed_fn, steps=steps or self.steps)
def partial_fit(self, x, y):
"""Incremental fit on a batch of samples.
This method is expected to be called several times consecutively
@ -282,7 +212,7 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
to converge, and you want to split up training into subparts.
Args:
X: matrix or tensor of shape [n_samples, n_features...]. Can be
x: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
y: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be
@ -292,33 +222,30 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Returns:
Returns self.
"""
return self.fit(X, y)
def _predict(self, X, axis=-1, batch_size=None):
if not self._initialized:
raise _sklearn.NotFittedError()
return self.fit(x, y)
def _predict(self, x, axis=-1, batch_size=None):
if self._graph is None:
raise NotFittedError()
# Use the batch size for fitting if the user did not specify one.
if batch_size is None:
batch_size = self.batch_size
self._graph.add_to_collection('IS_TRAINING', False)
predict_data_feeder = setup_predict_data_feeder(X, batch_size=batch_size)
preds = []
dropouts = self._graph.get_collection(DROPOUTS)
feed_dict = {prob: 1.0 for prob in dropouts}
for data in predict_data_feeder:
feed_dict[self._inp] = data
predictions_for_batch = self._session.run(self._model_predictions,
feed_dict)
if self.n_classes > 1 and axis != -1:
preds.append(predictions_for_batch.argmax(axis=axis))
else:
preds.append(predictions_for_batch)
predict_data_feeder = setup_train_data_feeder(
x, None, n_classes=None,
batch_size=batch_size,
shuffle=False, epochs=1)
return np.concatenate(preds, axis=0)
preds = self._infer_model(
input_fn=predict_data_feeder.input_builder,
feed_fn=predict_data_feeder.get_feed_dict_fn())
if self.n_classes > 1 and axis != -1:
preds = preds['predictions'].argmax(axis=axis)
else:
preds = preds['predictions']
return preds
def predict(self, X, axis=1, batch_size=None):
def predict(self, x, axis=1, batch_size=None):
"""Predict class or regression for X.
For a classification model, the predicted class for each sample in X is
@ -326,7 +253,7 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
returned.
Args:
X: array-like matrix, [n_samples, n_features...] or iterator.
x: array-like matrix, [n_samples, n_features...] or iterator.
axis: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -338,13 +265,13 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
y: array of shape [n_samples]. The predicted classes or predicted
value.
"""
return self._predict(X, axis=axis, batch_size=batch_size)
return self._predict(x, axis=axis, batch_size=batch_size)
def predict_proba(self, X, batch_size=None):
def predict_proba(self, x, batch_size=None):
"""Predict class probability of the input samples X.
Args:
X: array-like matrix, [n_samples, n_features...] or iterator.
x: array-like matrix, [n_samples, n_features...] or iterator.
batch_size: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -352,7 +279,7 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
y: array of shape [n_samples, n_classes]. The predicted
probabilities for each class.
"""
return self._predict(X, batch_size=batch_size)
return self._predict(x, batch_size=batch_size)
def get_tensor(self, name):
"""Returns tensor by name.
@ -374,7 +301,9 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Returns:
Numpy array - value of the tensor.
"""
return self._session.run(self.get_tensor(name))
if name.endswith(':0'):
name = name[:-2]
return checkpoints.load_variable(self.model_dir, name)
def get_variable_names(self):
"""Returns list of all variable names in this model.
@ -382,8 +311,7 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Returns:
List of names.
"""
with self._graph.as_default():
return [v.name for v in variables.all_variables()]
return [name for name, _ in checkpoints.list_variables(self.model_dir)]
def save(self, path):
"""Saves checkpoints and graph to given path.
@ -391,17 +319,12 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Args:
path: Folder to save model to.
"""
if not self._initialized:
raise _sklearn.NotFittedError()
if self._graph is None:
raise NotFittedError
# Currently Saver requires absolute path to work correctly.
path = os.path.abspath(path)
# Copy model dir into new path.
_copy_dir(self.model_dir, path)
if not os.path.exists(path):
os.makedirs(path)
if not os.path.isdir(path):
raise ValueError('Path %s should be a directory to save'
'checkpoints and graph.' % path)
# Save model definition.
all_params = self.get_params()
params = {}
@ -414,25 +337,6 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
default=lambda o: o.__dict__ if hasattr(o, '__dict__') else None)
_write_with_backup(os.path.join(path, 'model.def'), model_def)
# Save checkpoints.
endpoints = '%s\n%s\n%s\n%s' % (self._inp.name, self._out.name,
self._model_predictions.name,
self._model_loss.name)
_write_with_backup(os.path.join(path, 'endpoints'), endpoints)
# Save graph definition.
_write_with_backup(
os.path.join(path, 'graph.pbtxt'), str(self._graph.as_graph_def()))
# Save saver definition.
_write_with_backup(
os.path.join(path, 'saver.pbtxt'), str(self._saver.as_saver_def()))
# Save checkpoints.
self._saver.save(self._session,
os.path.join(path, 'model'),
global_step=self._global_step)
def _restore(self, path):
"""Restores this estimator from given path.
@ -442,57 +346,7 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Args:
path: Path to checkpoints and other information.
"""
# Currently Saver requires absolute path to work correctly.
path = os.path.abspath(path)
self._graph = ops.Graph()
with self._graph.as_default():
endpoints_filename = os.path.join(path, 'endpoints')
if not os.path.exists(endpoints_filename):
raise ValueError("Restore folder doesn't contain endpoints.")
with gfile.Open(endpoints_filename) as foutputs:
endpoints = foutputs.read().split('\n')
graph_filename = os.path.join(path, 'graph.pbtxt')
if not os.path.exists(graph_filename):
raise ValueError("Restore folder doesn't contain graph definition.")
with gfile.Open(graph_filename) as fgraph:
graph_def = graph_pb2.GraphDef()
text_format.Merge(fgraph.read(), graph_def)
(self._inp, self._out, self._model_predictions,
self._model_loss) = importer.import_graph_def(
graph_def, name='', return_elements=endpoints)
saver_filename = os.path.join(path, 'saver.pbtxt')
if not os.path.exists(saver_filename):
raise ValueError("Restore folder doesn't contain saver definition.")
with gfile.Open(saver_filename) as fsaver:
saver_def = train.SaverDef()
text_format.Merge(fsaver.read(), saver_def)
self._saver = train.Saver(saver_def=saver_def)
# Restore trainer
self._global_step = self._graph.get_tensor_by_name('global_step:0')
self._train = self._graph.get_operation_by_name('OptimizeLoss/train')
# Restore summaries.
self._summaries = self._graph.get_operation_by_name(
'MergeSummary/MergeSummary')
# Restore session.
if not isinstance(self._config, RunConfig):
self._config = RunConfig(verbose=self.verbose)
self._session = session.Session(self._config.master,
config=self._config.tf_config)
checkpoint_path = train.latest_checkpoint(path)
if checkpoint_path is None:
raise ValueError(
'Missing checkpoint files in the %s. Please '
'make sure you are you have checkpoint file that describes '
'latest checkpoints and appropriate checkpoints are there. '
'If you have moved the folder, you at this point need to '
'update manually update the paths in the checkpoint file.' % path)
self._saver.restore(self._session, checkpoint_path)
# Set to be initialized.
self._initialized = True
raise NotImplementedError
# pylint: disable=unused-argument
@classmethod
@ -549,7 +403,7 @@ class TensorFlowBaseTransformer(TensorFlowEstimator, _sklearn.TransformerMixin):
def fit(self, X, y=None, monitor=None, logdir=None):
"""Fit a transformer."""
return(super(TensorFlowBaseTransformer, self).fit(X, y, monitor=None, logdir=None))
return(super(TensorFlowBaseTransformer, self).fit(X, y, monitors=None, logdir=None))
def fit_transform(self, X, y=None, monitor=None, logdir=None):
"""Fit transformer and transform X using trained transformer."""

View File

@ -16,11 +16,176 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from tensorflow.contrib.learn.python.learn.estimators import _sklearn
from tensorflow.contrib.learn.python.learn.estimators.base import TensorFlowEstimator
from tensorflow.contrib import layers
from tensorflow.contrib.learn.python.learn import models
from tensorflow.contrib.learn.python.learn.estimators import _sklearn
from tensorflow.contrib.learn.python.learn.estimators import dnn_linear_combined
from tensorflow.contrib.learn.python.learn.estimators.base import TensorFlowEstimator
from tensorflow.python.ops import nn
# TODO(ipolosukhin): Merge thirdparty DNN with this.
class DNNClassifier(dnn_linear_combined.DNNLinearCombinedClassifier):
"""A classifier for TensorFlow DNN models.
Example:
```
installed_app_id = sparse_column_with_hash_bucket("installed_id", 1e6)
impression_app_id = sparse_column_with_hash_bucket("impression_id", 1e6)
installed_emb = embedding_column(installed_app_id, dimension=16,
combiner="sum")
impression_emb = embedding_column(impression_app_id, dimension=16,
combiner="sum")
estimator = DNNClassifier(
feature_columns=[installed_emb, impression_emb],
hidden_units=[1024, 512, 256])
# Input builders
def input_fn_train: # returns X, Y
pass
estimator.train(input_fn_train)
def input_fn_eval: # returns X, Y
pass
estimator.evaluate(input_fn_eval)
estimator.predict(x)
```
Input of `fit`, `train`, and `evaluate` should have following features,
otherwise there will be a `KeyError`:
if `weight_column_name` is not `None`, a feature with
`key=weight_column_name` whose value is a `Tensor`.
for each `column` in `feature_columns`:
- if `column` is a `SparseColumn`, a feature with `key=column.name`
whose `value` is a `SparseTensor`.
- if `column` is a `RealValuedColumn, a feature with `key=column.name`
whose `value` is a `Tensor`.
- if `feauture_columns` is None, then `input` must contains only real
valued `Tensor`.
Parameters:
hidden_units: List of hidden units per layer. All layers are fully
connected. Ex. [64, 32] means first layer has 64 nodes and second one has
32.
feature_columns: An iterable containing all the feature columns used by the
model. All items in the set should be instances of classes derived from
`FeatureColumn`.
model_dir: Directory to save model parameters, graph and etc.
n_classes: number of target classes. Default is binary classification.
It must be greater than 1.
weight_column_name: A string defining feature column name representing
weights. It is used to down weight or boost examples during training. It
will be multiplied by the loss of the example.
optimizer: An instance of `tf.Optimizer` used to train the model. If `None`,
will use an Adagrad optimizer.
activation_fn: Activation function applied to each layer. If `None`, will
use `tf.nn.relu`.
"""
def __init__(self,
hidden_units,
feature_columns=None,
model_dir=None,
n_classes=2,
weight_column_name=None,
optimizer=None,
activation_fn=nn.relu):
super(DNNClassifier, self).__init__(n_classes=n_classes,
weight_column_name=weight_column_name,
dnn_feature_columns=feature_columns,
dnn_optimizer=optimizer,
dnn_hidden_units=hidden_units,
dnn_activation_fn=activation_fn)
def _get_train_ops(self, features, targets):
"""See base class."""
if self._dnn_feature_columns is None:
self._dnn_feature_columns = layers.infer_real_valued_columns(features)
return super(DNNClassifier, self)._get_train_ops(features, targets)
class DNNRegressor(dnn_linear_combined.DNNLinearCombinedRegressor):
"""A regressor for TensorFlow DNN models.
Example:
```
installed_app_id = sparse_column_with_hash_bucket("installed_id", 1e6)
impression_app_id = sparse_column_with_hash_bucket("impression_id", 1e6)
installed_emb = embedding_column(installed_app_id, dimension=16,
combiner="sum")
impression_emb = embedding_column(impression_app_id, dimension=16,
combiner="sum")
estimator = DNNRegressor(
feature_columns=[installed_emb, impression_emb],
hidden_units=[1024, 512, 256])
# Input builders
def input_fn_train: # returns X, Y
pass
estimator.train(input_fn_train)
def input_fn_eval: # returns X, Y
pass
estimator.evaluate(input_fn_eval)
estimator.predict(x)
```
Input of `fit`, `train`, and `evaluate` should have following features,
otherwise there will be a `KeyError`:
if `weight_column_name` is not `None`, a feature with
`key=weight_column_name` whose value is a `Tensor`.
for each `column` in `feature_columns`:
- if `column` is a `SparseColumn`, a feature with `key=column.name`
whose `value` is a `SparseTensor`.
- if `column` is a `RealValuedColumn, a feature with `key=column.name`
whose `value` is a `Tensor`.
- if `feauture_columns` is None, then `input` must contains only real
valued `Tensor`.
Parameters:
hidden_units: List of hidden units per layer. All layers are fully
connected. Ex. [64, 32] means first layer has 64 nodes and second one has
32.
feature_columns: An iterable containing all the feature columns used by the
model. All items in the set should be instances of classes derived from
`FeatureColumn`.
model_dir: Directory to save model parameters, graph and etc.
weight_column_name: A string defining feature column name representing
weights. It is used to down weight or boost examples during training. It
will be multiplied by the loss of the example.
optimizer: An instance of `tf.Optimizer` used to train the model. If `None`,
will use an Adagrad optimizer.
activation_fn: Activation function applied to each layer. If `None`, will
use `tf.nn.relu`.
"""
def __init__(self,
hidden_units,
feature_columns=None,
model_dir=None,
weight_column_name=None,
optimizer=None,
activation_fn=nn.relu):
super(DNNRegressor, self).__init__(weight_column_name=weight_column_name,
dnn_feature_columns=feature_columns,
dnn_optimizer=optimizer,
dnn_hidden_units=hidden_units,
dnn_activation_fn=activation_fn)
def _get_train_ops(self, features, targets):
"""See base class."""
if self._dnn_feature_columns is None:
self._dnn_feature_columns = layers.infer_real_valued_columns(features)
return super(DNNRegressor, self)._get_train_ops(features, targets)
# TODO(ipolosukhin): Deprecate this class in favor of DNNClassifier.
class TensorFlowDNNClassifier(TensorFlowEstimator, _sklearn.ClassifierMixin):
"""TensorFlow DNN Classifier model.
@ -84,16 +249,16 @@ class TensorFlowDNNClassifier(TensorFlowEstimator, _sklearn.ClassifierMixin):
@property
def weights_(self):
"""Returns weights of the DNN weight layers."""
return [self._session.run(w)
return [self.get_tensor_value(w.name)
for w in self._graph.get_collection('dnn_weights')
] + [self.get_tensor_value('logistic_regression/weights:0')]
] + [self.get_tensor_value('logistic_regression/weights')]
@property
def bias_(self):
"""Returns bias of the DNN's bias layers."""
return [self._session.run(b)
return [self.get_tensor_value(b.name)
for b in self._graph.get_collection('dnn_biases')
] + [self.get_tensor_value('logistic_regression/bias:0')]
] + [self.get_tensor_value('logistic_regression/bias')]
class TensorFlowDNNRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@ -157,13 +322,13 @@ class TensorFlowDNNRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@property
def weights_(self):
"""Returns weights of the DNN weight layers."""
return [self._session.run(w)
return [self.get_tensor_value(w.name)
for w in self._graph.get_collection('dnn_weights')
] + [self.get_tensor_value('linear_regression/weights:0')]
] + [self.get_tensor_value('linear_regression/weights')]
@property
def bias_(self):
"""Returns bias of the DNN's bias layers."""
return [self._session.run(b)
return [self.get_tensor_value(b.name)
for b in self._graph.get_collection('dnn_biases')
] + [self.get_tensor_value('linear_regression/bias:0')]
] + [self.get_tensor_value('linear_regression/bias')]

View File

@ -0,0 +1,490 @@
# Copyright 2015 Google Inc. 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.
"""TensorFlow estimators for Linear and DNN joined training models."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import math
import six
from tensorflow.contrib import layers
from tensorflow.contrib import metrics as metrics_lib
from tensorflow.contrib.framework.python.ops import variables as variables
from tensorflow.contrib.learn.python.learn.estimators import estimator
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 gradients
from tensorflow.python.ops import logging_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import nn
from tensorflow.python.ops import parsing_ops
from tensorflow.python.ops import state_ops
# TODO(ispir): Increase test coverage
class _DNNLinearCombinedBaseEstimator(estimator.BaseEstimator):
"""An estimator for TensorFlow Linear and DNN joined training models.
Input of `fit`, `train`, and `evaluate` should have following features,
otherwise there will be a `KeyError`:
if `weight_column_name` is not `None`, a feature with
`key=weight_column_name` whose value is a `Tensor`.
for each `column` in `dnn_feature_columns` + `linear_feature_columns`:
- if `column` is a `SparseColumn`, a feature with `key=column.name`
whose `value` is a `SparseTensor`.
- if `column` is a `RealValuedColumn, a feature with `key=column.name`
whose `value` is a `Tensor`.
Parameters:
model_dir: Directory to save model parameters, graph and etc.
n_classes: number of target classes. Default is binary classification.
weight_column_name: A string defining feature column name representing
weights. It is used to down weight or boost examples during training. It
will be multiplied by the loss of the example.
linear_feature_columns: An iterable containing all the feature columns used
by linear part of the model. All items in the set should be instances of
classes derived from `FeatureColumn`.
linear_optimizer: An instance of `tf.Optimizer` used to apply gradients to
the linear part of the model. If `None`, will use a FTRL optimizer.
dnn_feature_columns: An iterable containing all the feature columns used by
deep part of the model. All items in the set should be instances of
classes derived from `FeatureColumn`.
dnn_hidden_units: List of hidden units per layer. All layers are fully
connected.
dnn_optimizer: An instance of `tf.Optimizer` used to apply gradients to the
deep part of the model. If `None`, will use an Adagrad optimizer.
dnn_activation_fn: Activation function applied to each layer. If `None`,
will use `tf.nn.relu`.
Raises:
ValueError: If both linear_feature_columns and dnn_features_columns are
empty at the same time.
"""
def __init__(self,
model_dir=None,
n_classes=2,
weight_column_name=None,
linear_feature_columns=None,
linear_optimizer=None,
dnn_feature_columns=None,
dnn_optimizer=None,
dnn_hidden_units=None,
dnn_activation_fn=nn.relu):
super(_DNNLinearCombinedBaseEstimator, self).__init__(model_dir=model_dir)
self._n_classes = n_classes
self._weight_column_name = weight_column_name
self._linear_feature_columns = linear_feature_columns
self._linear_optimizer = linear_optimizer
self._dnn_feature_columns = dnn_feature_columns
self._dnn_optimizer = dnn_optimizer
self._dnn_hidden_units = dnn_hidden_units
self._dnn_activation_fn = dnn_activation_fn
if self._dnn_activation_fn is None:
self._dnn_activation_fn = nn.relu
self._dnn_weight_collection = "DNNLinearCombined_dnn"
self._linear_weight_collection = "DNNLinearCombined_linear"
def _get_train_ops(self, features, targets):
"""See base class."""
global_step = variables.get_global_step()
assert global_step
loss = self._loss(
self._logits(features), targets, self._get_weight_tensor(features))
logging_ops.scalar_summary("loss", loss)
linear_vars = self._get_linear_vars()
dnn_vars = self._get_dnn_vars()
grads = gradients.gradients(loss, dnn_vars + linear_vars)
dnn_grads = grads[0:len(dnn_vars)]
linear_grads = grads[len(dnn_vars):]
train_ops = self._get_linear_training_ops(
linear_grads, linear_vars) + self._get_dnn_training_ops(dnn_grads,
dnn_vars)
train_step = control_flow_ops.group(*train_ops, name="combined_training_op")
with ops.control_dependencies([train_step]):
with ops.get_default_graph().colocate_with(global_step):
return state_ops.assign_add(global_step, 1).op, loss
def _get_eval_ops(self, features, targets, metrics):
"""See base class."""
predictions = self._get_predict_ops(features)
result = {}
for name, metric in six.iteritems(metrics):
result[name] = metric(predictions, targets,
self._get_weight_tensor(features))
return result
def _get_default_metric_functions(self):
"""See base class."""
def _compute_loss(logits, targets, weights=None):
return self._loss(logits, targets, weight_tensor=weights)
def _compute_accuracy(logits, targets, weights=None):
if self._n_classes > 2:
_, predictions = nn.top_k(logits, 1)
else:
predictions = array_ops.reshape(logits, [-1])
predictions = math_ops.greater(predictions,
array_ops.zeros_like(predictions))
targets = array_ops.reshape(targets, [-1])
return metrics_lib.accuracy(
math_ops.to_int32(predictions), math_ops.to_int32(targets), weights)
result = {"loss": _compute_loss}
if self._n_classes > 1:
result["accuracy"] = _compute_accuracy
return result
def _get_predict_ops(self, features):
return self._logits(features)
def _get_feature_ops_from_example(self, examples_batch):
column_types = layers.create_dict_for_parse_example(
self._get_linear_feature_columns() + self._get_dnn_feature_columns())
features = parsing_ops.parse_example(examples_batch, column_types)
return features
def _num_label_columns(self):
return 1 if self._n_classes <= 2 else self._n_classes
def _get_linear_feature_columns(self):
return sorted(
set(self._linear_feature_columns),
key=lambda x: x.key) if self._linear_feature_columns else None
def _get_dnn_feature_columns(self):
return sorted(set(
self._dnn_feature_columns)) if self._dnn_feature_columns else None
def _dnn_logits(self, features):
net = layers.input_from_feature_columns(
features,
self._get_dnn_feature_columns(),
weight_collections=[self._dnn_weight_collection])
for layer_id, num_hidden_units in enumerate(self._dnn_hidden_units):
net = layers.legacy_fully_connected(
net,
num_hidden_units,
activation_fn=self._dnn_activation_fn,
weight_collections=[self._dnn_weight_collection],
bias_collections=[self._dnn_weight_collection],
name="hiddenlayer_%d" % layer_id)
self._add_hidden_layer_summary(net, "hiddenlayer_%d" % layer_id)
logit = layers.legacy_fully_connected(
net,
self._num_label_columns(),
weight_collections=[self._dnn_weight_collection],
bias_collections=[self._dnn_weight_collection],
name="dnn_logit")
self._add_hidden_layer_summary(logit, "dnn_logit")
return logit
def _add_hidden_layer_summary(self, value, tag):
# TODO(zakaria): Move this code to tf.learn and add test.
logging_ops.scalar_summary("%s:fraction_of_zero_values" % tag,
nn.zero_fraction(value))
logging_ops.histogram_summary("%s:activation" % tag, value)
def _linear_logits(self, features):
logits, _, _ = layers.weighted_sum_from_feature_columns(
columns_to_tensors=features,
feature_columns=self._get_linear_feature_columns(),
num_outputs=self._num_label_columns(),
weight_collections=[self._linear_weight_collection],
name="linear")
return logits
def _get_feature_dict(self, features):
if isinstance(features, dict):
return features
return {"": features}
def _logits(self, features):
if not (self._get_linear_feature_columns() or
self._get_dnn_feature_columns()):
raise ValueError("Either linear_feature_columns or dnn_feature_columns "
"should be defined.")
features = self._get_feature_dict(features)
if self._get_linear_feature_columns() and self._get_dnn_feature_columns():
return self._linear_logits(features) + self._dnn_logits(features)
elif self._get_dnn_feature_columns():
return self._dnn_logits(features)
else:
return self._linear_logits(features)
def _get_weight_tensor(self, features):
if not self._weight_column_name:
return None
else:
return math_ops.to_float(features[self._weight_column_name])
def _loss(self, logits, target, weight_tensor):
if self._n_classes < 2:
loss_vec = math_ops.square(logits - math_ops.to_float(target))
elif self._n_classes == 2:
loss_vec = nn.sigmoid_cross_entropy_with_logits(logits,
math_ops.to_float(target))
else:
loss_vec = nn.sparse_softmax_cross_entropy_with_logits(
logits, array_ops.reshape(target, [-1]))
if weight_tensor is None:
return math_ops.reduce_mean(loss_vec, name="loss")
else:
loss_vec = array_ops.reshape(loss_vec, shape=(-1,))
loss_vec = math_ops.mul(
loss_vec, array_ops.reshape(weight_tensor, shape=(-1,)))
return math_ops.div(
math_ops.reduce_sum(loss_vec),
math_ops.to_float(math_ops.reduce_sum(weight_tensor)),
name="loss")
def _get_linear_vars(self):
if self._get_linear_feature_columns():
return ops.get_collection(self._linear_weight_collection)
return []
def _get_linear_training_ops(self, linear_grads, linear_vars):
if self._get_linear_feature_columns():
self._linear_optimizer = self._get_optimizer(
self._linear_optimizer,
default_optimizer="Ftrl",
default_learning_rate=1. / math.sqrt(len(
self._get_linear_feature_columns())))
return [
self._linear_optimizer.apply_gradients(zip(linear_grads, linear_vars))
]
return []
def _get_dnn_vars(self):
if self._get_dnn_feature_columns():
return ops.get_collection(self._dnn_weight_collection)
return []
def _get_dnn_training_ops(self, dnn_grads, dnn_vars):
if self._get_dnn_feature_columns():
self._dnn_optimizer = self._get_optimizer(self._dnn_optimizer,
default_optimizer="Adagrad",
default_learning_rate=0.05)
return [self._dnn_optimizer.apply_gradients(zip(dnn_grads, dnn_vars))]
return []
def _get_optimizer(self, optimizer, default_optimizer, default_learning_rate):
if optimizer is None:
optimizer = default_optimizer
if isinstance(optimizer, six.string_types):
optimizer = layers.OPTIMIZER_CLS_NAMES[optimizer](
learning_rate=default_learning_rate)
return optimizer
class DNNLinearCombinedClassifier(_DNNLinearCombinedBaseEstimator):
"""A classifier for TensorFlow Linear and DNN joined training models.
Example:
```
installed_app_id = sparse_column_with_hash_bucket("installed_id", 1e6)
impression_app_id = sparse_column_with_hash_bucket("impression_id", 1e6)
installed_x_impression = crossed_column(
[installed_app_id, impression_app_id])
installed_emb = embedding_column(installed_app_id, dimension=16,
combiner="sum")
impression_emb = embedding_column(impression_app_id, dimension=16,
combiner="sum")
estimator = DNNLinearCombinedClassifier(
# common settings
n_classes, weight_column_name,
# wide settings
linear_feature_columns=[installed_x_impression],
linear_optimizer=tf.train.FtrlOptimizer(...),
# deep settings
dnn_feature_columns=[installed_emb, impression_emb],
dnn_hidden_units=[1000, 500, 100],
dnn_optimizer=tf.train.AdagradOptimizer(...))
# Input builders
def input_fn_train: # returns X, Y
...
def input_fn_eval: # returns X, Y
...
estimator.train(input_fn_train)
estimator.evaluate(input_fn_eval)
estimator.predict(x)
```
Input of `fit`, `train`, and `evaluate` should have following features,
otherwise there will be a `KeyError`:
if `weight_column_name` is not `None`, a feature with
`key=weight_column_name` whose value is a `Tensor`.
for each `column` in `dnn_feature_columns` + `linear_feature_columns`:
- if `column` is a `SparseColumn`, a feature with `key=column.name`
whose `value` is a `SparseTensor`.
- if `column` is a `RealValuedColumn, a feature with `key=column.name`
whose `value` is a `Tensor`.
Parameters:
model_dir: Directory to save model parameters, graph and etc.
n_classes: number of target classes. Default is binary classification.
weight_column_name: A string defining feature column name representing
weights. It is used to down weight or boost examples during training. It
will be multiplied by the loss of the example.
linear_feature_columns: An iterable containing all the feature columns used
by linear part of the model. All items in the set must be instances of
classes derived from `FeatureColumn`.
linear_optimizer: An instance of `tf.Optimizer` used to apply gradients to
the linear part of the model. If `None`, will use a FTRL optimizer.
dnn_feature_columns: An iterable containing all the feature columns used by
deep part of the model. All items in the set must be instances of
classes derived from `FeatureColumn`.
dnn_hidden_units: List of hidden units per layer. All layers are fully
connected.
dnn_optimizer: An instance of `tf.Optimizer` used to apply gradients to the
deep part of the model. If `None`, will use an Adagrad optimizer.
dnn_activation_fn: Activation function applied to each layer. If `None`,
will use `tf.nn.relu`.
Raises:
ValueError: If both linear_feature_columns and dnn_features_columns are
empty at the same time.
ValueError: If both n_classes < 2.
"""
def __init__(self,
model_dir=None,
n_classes=2,
weight_column_name=None,
linear_feature_columns=None,
linear_optimizer=None,
dnn_feature_columns=None,
dnn_optimizer=None,
dnn_hidden_units=None,
dnn_activation_fn=nn.relu):
if n_classes < 2:
raise ValueError("n_classes should be greater than 1. Given: {}".format(
n_classes))
super(DNNLinearCombinedClassifier, self).__init__(
model_dir=model_dir,
n_classes=n_classes,
weight_column_name=weight_column_name,
linear_feature_columns=linear_feature_columns,
linear_optimizer=linear_optimizer,
dnn_feature_columns=dnn_feature_columns,
dnn_optimizer=dnn_optimizer,
dnn_hidden_units=dnn_hidden_units,
dnn_activation_fn=dnn_activation_fn)
class DNNLinearCombinedRegressor(_DNNLinearCombinedBaseEstimator):
"""A regressor for TensorFlow Linear and DNN joined training models.
Example:
```
installed_app_id = sparse_column_with_hash_bucket("installed_id", 1e6)
impression_app_id = sparse_column_with_hash_bucket("impression_id", 1e6)
installed_x_impression = crossed_column(
[installed_app_id, impression_app_id])
installed_emb = embedding_column(installed_app_id, dimension=16,
combiner="sum")
impression_emb = embedding_column(impression_app_id, dimension=16,
combiner="sum")
estimator = DNNLinearCombinedClassifier(
# common settings
n_classes, weight_column_name,
# wide settings
linear_feature_columns=[installed_x_impression],
linear_optimizer=tf.train.FtrlOptimizer(...),
# deep settings
dnn_feature_columns=[installed_emb, impression_emb],
dnn_hidden_units=[1000, 500, 100],
dnn_optimizer=tf.train.AdagradOptimizer(...))
# Input builders
def input_fn_train: # returns X, Y
...
def input_fn_eval: # returns X, Y
...
estimator.train(input_fn_train)
estimator.evaluate(input_fn_eval)
estimator.predict(x)
```
Input of `fit`, `train`, and `evaluate` should have following features,
otherwise there will be a `KeyError`:
if `weight_column_name` is not `None`, a feature with
`key=weight_column_name` whose value is a `Tensor`.
for each `column` in `dnn_feature_columns` + `linear_feature_columns`:
- if `column` is a `SparseColumn`, a feature with `key=column.name`
whose `value` is a `SparseTensor`.
- if `column` is a `RealValuedColumn, a feature with `key=column.name`
whose `value` is a `Tensor`.
Parameters:
model_dir: Directory to save model parameters, graph and etc.
weight_column_name: A string defining feature column name representing
weights. It is used to down weight or boost examples during training. It
will be multiplied by the loss of the example.
linear_feature_columns: An iterable containing all the feature columns used
by linear part of the model. All items in the set must be instances of
classes derived from `FeatureColumn`.
linear_optimizer: An instance of `tf.Optimizer` used to apply gradients to
the linear part of the model. If `None`, will use a FTRL optimizer.
dnn_feature_columns: An iterable containing all the feature columns used by
deep part of the model. All items in the set must be instances of
classes derived from `FeatureColumn`.
dnn_hidden_units: List of hidden units per layer. All layers are fully
connected.
dnn_optimizer: An instance of `tf.Optimizer` used to apply gradients to the
deep part of the model. If `None`, will use an Adagrad optimizer.
dnn_activation_fn: Activation function applied to each layer. If None, will
use `tf.nn.relu`.
Raises:
ValueError: If both linear_feature_columns and dnn_features_columns are
empty at the same time.
"""
def __init__(self,
model_dir=None,
weight_column_name=None,
linear_feature_columns=None,
linear_optimizer=None,
dnn_feature_columns=None,
dnn_optimizer=None,
dnn_hidden_units=None,
dnn_activation_fn=nn.relu):
super(DNNLinearCombinedRegressor, self).__init__(
model_dir=model_dir,
n_classes=0,
weight_column_name=weight_column_name,
linear_feature_columns=linear_feature_columns,
linear_optimizer=linear_optimizer,
dnn_feature_columns=dnn_feature_columns,
dnn_optimizer=dnn_optimizer,
dnn_hidden_units=dnn_hidden_units,
dnn_activation_fn=dnn_activation_fn)

View File

@ -0,0 +1,254 @@
# Copyright 2015 Google Inc. 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 DNNLinearCombinedEstimators."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
def _get_quantile_based_buckets(feature_values, num_buckets):
quantiles = np.percentile(
np.array(feature_values), ([100 * (i + 1.) / (num_buckets + 1.)
for i in range(num_buckets)]))
return list(quantiles)
def _prepare_iris_data_for_logistic_regression():
# Converts iris data to a logistic regression problem.
iris = tf.contrib.learn.datasets.load_iris()
ids = np.where((iris.target == 0) | (iris.target == 1))
iris = tf.contrib.learn.datasets.base.Dataset(data=iris.data[ids],
target=iris.target[ids])
return iris
def _iris_input_fn():
iris = _prepare_iris_data_for_logistic_regression()
return {
'feature': tf.constant(iris.data, dtype=tf.float32)
}, tf.constant(iris.target, shape=[100, 1], dtype=tf.int32)
class DNNLinearCombinedClassifierTest(tf.test.TestCase):
def testLogisticRegression_MatrixData(self):
"""Tests binary classification using matrix data as input."""
iris = _prepare_iris_data_for_logistic_regression()
cont_features = [
tf.contrib.layers.real_valued_column('feature', dimension=4)]
bucketized_feature = [tf.contrib.layers.bucketized_column(
cont_features[0], _get_quantile_based_buckets(iris.data, 10))]
classifier = tf.contrib.learn.DNNLinearCombinedClassifier(
linear_feature_columns=bucketized_feature,
dnn_feature_columns=cont_features,
dnn_hidden_units=[3, 3])
classifier.train(_iris_input_fn, steps=100)
scores = classifier.evaluate(input_fn=_iris_input_fn, steps=100)
self.assertGreater(scores['accuracy'], 0.9)
def testLogisticRegression_TensorData(self):
"""Tests binary classification using Tensor data as input."""
def _input_fn():
iris = _prepare_iris_data_for_logistic_regression()
features = {}
for i in range(4):
# The following shows how to provide the Tensor data for
# RealValuedColumns.
features.update({
str(i): tf.reshape(tf.constant(iris.data[:, i], dtype=tf.float32),
[-1, 1])})
# The following shows how to provide the SparseTensor data for
# a SparseColumn.
features['dummy_sparse_column'] = tf.SparseTensor(
values=['en', 'fr', 'zh'],
indices=[[0, 0], [0, 1], [60, 0]],
shape=[len(iris.target), 2])
target = tf.reshape(tf.constant(iris.target, dtype=tf.float32), [-1, 1])
return features, target
iris = _prepare_iris_data_for_logistic_regression()
cont_features = [tf.contrib.layers.real_valued_column(str(i))
for i in range(4)]
linear_features = [
tf.contrib.layers.bucketized_column(
cont_features[i], _get_quantile_based_buckets(iris.data[:, str(i)],
10)) for i in range(4)
]
linear_features.append(tf.contrib.layers.sparse_column_with_hash_bucket(
'dummy_sparse_column', hash_bucket_size=100))
classifier = tf.contrib.learn.DNNLinearCombinedClassifier(
linear_feature_columns=linear_features,
dnn_feature_columns=cont_features,
dnn_hidden_units=[3, 3])
classifier.train(input_fn=_input_fn, steps=100)
scores = classifier.evaluate(input_fn=_input_fn, steps=100)
self.assertGreater(scores['accuracy'], 0.9)
def testMultiClass(self):
"""Tests multi-class classification using matrix data as input.
Please see testLogisticRegression_TensorData() for how to use Tensor
data as input instead.
"""
iris = tf.contrib.learn.datasets.load_iris()
cont_features = [
tf.contrib.layers.real_valued_column('feature', dimension=4)]
bucketized_features = [
tf.contrib.layers.bucketized_column(
cont_features[0], _get_quantile_based_buckets(iris.data, 10))]
classifier = tf.contrib.learn.DNNLinearCombinedClassifier(
n_classes=3,
linear_feature_columns=bucketized_features,
dnn_feature_columns=cont_features,
dnn_hidden_units=[3, 3])
classifier.train(_iris_input_fn, steps=100)
scores = classifier.evaluate(input_fn=_iris_input_fn, steps=100)
self.assertGreater(scores['accuracy'], 0.9)
def testWeightColumn(self):
"""Tests weight column."""
def _input_fn_train():
# Create 4 rows, one of them (y = x), three of them (y=Not(x))
# First row has more weight than others. Model should fit (y=x) better
# than (y=Not(x)) due to the relative higher weight of the first row.
target = tf.constant([[1], [0], [0], [0]])
features = {
'x': tf.ones(shape=[4, 1], dtype=tf.float32),
'w': tf.constant([[100.], [3.], [2.], [2.]])
}
return features, target
def _input_fn_eval():
# Create 4 rows (y = x)
target = tf.constant([[1], [1], [1], [1]])
features = {
'x': tf.ones(shape=[4, 1], dtype=tf.float32),
'w': tf.constant([[1.], [1.], [1.], [1.]])
}
return features, target
classifier = tf.contrib.learn.DNNLinearCombinedClassifier(
weight_column_name='w',
linear_feature_columns=[tf.contrib.layers.real_valued_column('x')],
dnn_feature_columns=[tf.contrib.layers.real_valued_column('x')],
dnn_hidden_units=[3, 3])
classifier.train(input_fn=_input_fn_train, steps=100)
scores = classifier.evaluate(input_fn=_input_fn_eval,
steps=100)
# If there is no weight column, model should learn y=Not(x). All examples in
# eval data set are y=x. So if weight column is ignored, then accuracy
# should be zero.
self.assertGreater(scores['accuracy'], 0.9)
def testEvaluationShouldUseWeightColumn(self):
"""Tests weight column in evaluation."""
def _input_fn_train():
# Create 4 rows, one of them (y = x), three of them (y=Not(x))
# First row has more weight than others. Model should fit (y=x) better
# than (y=Not(x)) due to the relative higher weight of the first row.
target = tf.constant([[1], [0], [0], [0]])
features = {
'x': tf.ones(shape=[4, 1], dtype=tf.float32),
'w': tf.constant([[100.], [3.], [2.], [2.]])
}
return features, target
classifier = tf.contrib.learn.DNNLinearCombinedClassifier(
weight_column_name='w',
linear_feature_columns=[tf.contrib.layers.real_valued_column('x')],
dnn_feature_columns=[tf.contrib.layers.real_valued_column('x')],
dnn_hidden_units=[3, 3])
classifier.train(input_fn=_input_fn_train, steps=100)
scores = classifier.evaluate(input_fn=_input_fn_train, steps=100)
# If weight column is ignored, then accuracy should be 0.25. If it's not
# ignored, then it should be greater than 0.6.
self.assertGreater(scores['accuracy'], 0.6)
def testCustomOptimizerByObject(self):
"""Tests binary classification using matrix data as input."""
iris = _prepare_iris_data_for_logistic_regression()
cont_features = [
tf.contrib.layers.real_valued_column('feature', dimension=4)]
bucketized_features = [
tf.contrib.layers.bucketized_column(
cont_features[0], _get_quantile_based_buckets(iris.data, 10))]
classifier = tf.contrib.learn.DNNLinearCombinedClassifier(
linear_feature_columns=bucketized_features,
linear_optimizer=tf.train.FtrlOptimizer(learning_rate=0.1),
dnn_feature_columns=cont_features,
dnn_hidden_units=[3, 3],
dnn_optimizer=tf.train.AdagradOptimizer(learning_rate=0.1))
classifier.train(_iris_input_fn, steps=100)
scores = classifier.evaluate(input_fn=_iris_input_fn, steps=100)
self.assertGreater(scores['accuracy'], 0.9)
def testCustomOptimizerByString(self):
"""Tests binary classification using matrix data as input."""
iris = _prepare_iris_data_for_logistic_regression()
cont_features = [
tf.contrib.layers.real_valued_column('feature', dimension=4)]
bucketized_features = [
tf.contrib.layers.bucketized_column(
cont_features[0], _get_quantile_based_buckets(iris.data, 10))]
classifier = tf.contrib.learn.DNNLinearCombinedClassifier(
linear_feature_columns=bucketized_features,
linear_optimizer='Ftrl',
dnn_feature_columns=cont_features,
dnn_hidden_units=[3, 3],
dnn_optimizer='Adagrad')
classifier.train(_iris_input_fn, steps=100)
scores = classifier.evaluate(input_fn=_iris_input_fn, steps=100)
self.assertGreater(scores['accuracy'], 0.9)
class DNNLinearCombinedRegressorTest(tf.test.TestCase):
def testRegression(self):
"""Tests a regression problem."""
def _input_fn_train():
# Create 4 rows of (y = x)
target = tf.constant([[100.], [3.], [2.], [2.]])
features = {'x': tf.constant([[100.], [3.], [2.], [2.]])}
return features, target
classifier = tf.contrib.learn.DNNLinearCombinedRegressor(
linear_feature_columns=[tf.contrib.layers.real_valued_column('x')],
dnn_feature_columns=[tf.contrib.layers.real_valued_column('x')],
dnn_hidden_units=[3, 3])
classifier.train(input_fn=_input_fn_train, steps=100)
classifier.evaluate(input_fn=_input_fn_train, steps=1)
if __name__ == '__main__':
tf.test.main()

View File

@ -0,0 +1,77 @@
# Copyright 2015 Google Inc. 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 DNNEstimators."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
def _iris_input_fn():
iris = tf.contrib.learn.datasets.load_iris()
return {
'feature': tf.constant(iris.data, dtype=tf.float32)
}, tf.constant(iris.target, shape=[150, 1], dtype=tf.int32)
class DNNClassifierTest(tf.test.TestCase):
def testMultiClass(self):
"""Tests multi-class classification using matrix data as input."""
cont_features = [
tf.contrib.layers.real_valued_column('feature', dimension=4)]
classifier = tf.contrib.learn.DNNClassifier(n_classes=3,
feature_columns=cont_features,
hidden_units=[3, 3])
classifier.train(_iris_input_fn, steps=1000)
classifier.evaluate(input_fn=_iris_input_fn, steps=100)
# TODO(ispir): Enable accuracy check after resolving the randomness issue.
# self.assertGreater(scores['accuracy/mean'], 0.6)
class DNNRegressorTest(tf.test.TestCase):
def testRegression(self):
"""Tests multi-class classification using matrix data as input."""
cont_features = [
tf.contrib.layers.real_valued_column('feature', dimension=4)]
regressor = tf.contrib.learn.DNNRegressor(feature_columns=cont_features,
hidden_units=[3, 3])
regressor.train(_iris_input_fn, steps=1000)
regressor.evaluate(input_fn=_iris_input_fn, steps=100)
def boston_input_fn():
boston = tf.contrib.learn.datasets.load_boston()
features = tf.cast(tf.reshape(tf.constant(boston.data), [-1, 13]), tf.float32)
target = tf.cast(tf.reshape(tf.constant(boston.target), [-1, 1]), tf.float32)
return features, target
class InferedColumnTest(tf.test.TestCase):
def testTrain(self):
est = tf.contrib.learn.DNNRegressor(hidden_units=[3, 3])
est.train(input_fn=boston_input_fn, steps=1)
_ = est.evaluate(input_fn=boston_input_fn, steps=1)
if __name__ == '__main__':
tf.test.main()

View File

@ -21,12 +21,16 @@ import abc
import os
import tempfile
import time
import types
import numpy as np
import six
from tensorflow.contrib import framework as contrib_framework
from tensorflow.contrib import layers
from tensorflow.contrib import losses
from tensorflow.contrib.learn.python.learn import graph_actions
from tensorflow.contrib.learn.python.learn import monitors as monitors_lib
from tensorflow.contrib.learn.python.learn.estimators import _sklearn as sklearn
from tensorflow.contrib.learn.python.learn.estimators import run_config
from tensorflow.contrib.learn.python.learn.estimators import tensor_signature
@ -37,6 +41,8 @@ from tensorflow.contrib.learn.python.learn.io import data_feeder
from tensorflow.python.framework import ops
from tensorflow.python.framework import random_seed
from tensorflow.python.ops import control_flow_ops
from tensorflow.python.ops import logging_ops
from tensorflow.python.platform import tf_logging as logging
from tensorflow.python.training import device_setter
from tensorflow.python.training import saver
@ -89,7 +95,7 @@ def _get_predict_input_fn(x, batch_size):
df = data_feeder.setup_train_data_feeder(x, None,
n_classes=None,
batch_size=batch_size)
batch_size=batch_size, epochs=1)
return df.input_builder, df.get_feed_dict_fn()
@ -112,7 +118,7 @@ class BaseEstimator(sklearn.BaseEstimator):
# TODO(wicke): Remove this once launcher takes over config functionality
_Config = run_config.RunConfig # pylint: disable=invalid-name
def __init__(self, model_dir=None):
def __init__(self, model_dir=None, config=None):
# Model directory.
self._model_dir = model_dir
if self._model_dir is None:
@ -121,7 +127,10 @@ class BaseEstimator(sklearn.BaseEstimator):
self._model_dir)
# Create a run configuration
self._config = BaseEstimator._Config()
if config is None:
self._config = BaseEstimator._Config()
else:
self._config = config
# Set device function depending if there are replicas or not.
if self._config.num_ps_replicas > 0:
@ -136,6 +145,12 @@ class BaseEstimator(sklearn.BaseEstimator):
self._features_info = None
self._targets_info = None
self._graph = None
@property
def model_dir(self):
return self._model_dir
@abc.abstractproperty
def _get_train_ops(self, features, targets):
"""Method that builds model graph and returns trainer ops.
@ -204,7 +219,7 @@ class BaseEstimator(sklearn.BaseEstimator):
"""
return {}
def fit(self, x, y, steps, batch_size=32, monitor=None):
def fit(self, x, y, steps, batch_size=32, monitors=None):
"""Trains a model given training data X and y.
Args:
@ -216,8 +231,8 @@ class BaseEstimator(sklearn.BaseEstimator):
(class labels in classification, real numbers in regression).
steps: number of steps to train model for.
batch_size: minibatch size to use on the input, defaults to 32.
monitor: monitor object to print training progress and invoke
early stopping.
monitors: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
Returns:
Returns self.
@ -226,24 +241,24 @@ class BaseEstimator(sklearn.BaseEstimator):
return self._train_model(input_fn=input_fn,
feed_fn=feed_fn,
steps=steps,
monitor=monitor)
monitors=monitors)
def train(self, input_fn, steps, monitor=None):
def train(self, input_fn, steps, monitors=None):
"""Trains a model given input builder function.
Args:
input_fn: Input builder function, returns tuple of dicts or
dict and Tensor.
steps: number of steps to train model for.
monitor: monitor object to print training progress and invoke
early stopping.
monitors: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
Returns:
Returns self.
"""
return self._train_model(input_fn=input_fn, steps=steps, monitor=monitor)
return self._train_model(input_fn=input_fn, steps=steps, monitors=monitors)
def partial_fit(self, x, y, steps=1, batch_size=32, monitor=None):
def partial_fit(self, x, y, steps=1, batch_size=32, monitors=None):
"""Incremental fit on a batch of samples.
This method is expected to be called several times consecutively
@ -263,8 +278,8 @@ class BaseEstimator(sklearn.BaseEstimator):
(class label in classification, real numbers in regression).
steps: number of steps to train model for.
batch_size: minibatch size to use on the input, defaults to 32.
monitor: Monitor object to print training progress and invoke
early stopping.
monitors: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
Returns:
Returns self.
@ -273,7 +288,7 @@ class BaseEstimator(sklearn.BaseEstimator):
return self._train_model(input_fn=input_fn,
feed_fn=feed_fn,
steps=steps,
monitor=monitor)
monitors=monitors)
def evaluate(self, x=None, y=None, input_fn=None, feed_fn=None,
batch_size=32, steps=100, metrics=None):
@ -323,7 +338,7 @@ class BaseEstimator(sklearn.BaseEstimator):
Args:
x: features.
batch_size: OVerride default batch size.
batch_size: Override default batch size.
Returns:
Numpy array of predicted probabilities.
@ -338,20 +353,24 @@ class BaseEstimator(sklearn.BaseEstimator):
(str(features), str(self._features_info)))
else:
self._features_info = tensor_signature.create_signatures(features)
if self._targets_info is not None:
if not tensor_signature.tensors_compatible(targets, self._targets_info):
raise ValueError('Targets are incompatible with given information. '
'Given targets: %s, required signatures: %s.' %
(str(targets), str(self._targets_info)))
else:
self._targets_info = tensor_signature.create_signatures(targets)
if targets is not None:
if self._targets_info is not None:
if not tensor_signature.tensors_compatible(targets, self._targets_info):
raise ValueError('Targets are incompatible with given information. '
'Given targets: %s, required signatures: %s.' %
(str(targets), str(self._targets_info)))
else:
self._targets_info = tensor_signature.create_signatures(targets)
def _train_model(self,
input_fn,
steps,
feed_fn=None,
init_op=None,
init_feed_fn=None,
init_fn=None,
device_fn=None,
monitor=None,
monitors=None,
log_every_steps=100,
fail_on_nan_loss=True):
if self._config.execution_mode not in ('all', 'train'):
@ -369,24 +388,42 @@ class BaseEstimator(sklearn.BaseEstimator):
# Device allocation
device_fn = device_fn or self._device_fn
with ops.Graph().as_default() as g, g.device(device_fn):
self._graph = ops.Graph()
with self._graph.as_default() as g, g.device(device_fn):
random_seed.set_random_seed(self._config.tf_random_seed)
global_step = contrib_framework.create_global_step(g)
features, targets = input_fn()
self._check_inputs(features, targets)
train_op, loss_op = self._get_train_ops(features, targets)
# Add default monitors.
if monitors is None:
monitors = []
monitors += monitors_lib.get_default_monitors(
loss_op=loss_op,
summary_op=logging_ops.get_summary_op(),
save_summary_steps=100)
# Setup monitors.
for monitor in monitors:
monitor.set_estimator(self)
return train(
graph=g,
output_dir=self._model_dir,
train_op=train_op,
loss_op=loss_op,
global_step_tensor=global_step,
init_op=init_op,
init_feed_dict=init_feed_fn() if init_feed_fn is not None else None,
init_fn=init_fn,
log_every_steps=log_every_steps,
supervisor_is_chief=(self._config.task == 0),
supervisor_master=self._config.master,
feed_fn=feed_fn,
max_steps=steps,
fail_on_nan_loss=fail_on_nan_loss)
fail_on_nan_loss=fail_on_nan_loss,
monitors=monitors)
def _evaluate_model(self, input_fn, steps, feed_fn=None, metrics=None):
if self._config.execution_mode not in ('all', 'evaluate', 'eval_evalset'):
@ -413,22 +450,41 @@ class BaseEstimator(sklearn.BaseEstimator):
max_steps=steps)
return eval_results
def _infer_model(self, x, batch_size=None, axis=None, proba=False):
def _infer_model(self,
x=None, input_fn=None, feed_fn=None,
batch_size=None, axis=None, proba=False):
# Converts inputs into tf.DataFrame / tf.Series.
batch_size = -1 if batch_size is None else batch_size
input_fn, feed_fn = _get_predict_input_fn(x, batch_size)
if x is not None:
input_fn, feed_fn = _get_predict_input_fn(x, batch_size)
checkpoint_path = saver.latest_checkpoint(self._model_dir)
with ops.Graph().as_default() as g:
random_seed.set_random_seed(self._config.tf_random_seed)
contrib_framework.create_global_step(g)
features, _ = input_fn()
feed_dict = feed_fn() if feed_fn is not None else None
predictions = self._get_predict_ops(features)
if not isinstance(predictions, dict):
predictions = {'predictions': predictions}
# TODO(ipolosukhin): Support batching
return infer(checkpoint_path, predictions, feed_dict=feed_dict)
if feed_fn is None:
return infer(checkpoint_path, predictions)
preds = {}
while True:
try:
feed_dict = feed_fn()
except StopIteration:
break
if feed_dict is None:
break
outputs = infer(checkpoint_path, predictions, feed_dict=feed_dict)
for key in outputs:
if key not in preds:
preds[key] = []
preds[key].append(outputs[key])
for key in preds:
preds[key] = np.concatenate(preds[key], axis=0)
return preds
class Estimator(BaseEstimator):
@ -449,16 +505,18 @@ class Estimator(BaseEstimator):
(like tf.train.GradientDescentOptimizer).
clip_gradients: clip_norm value for call to `clip_by_global_norm`. None
denotes no gradient clipping.
config: Configuration object.
"""
def __init__(self,
model_fn=None,
model_dir=None,
classification=True,
learning_rate=0.01,
optimizer='SGD',
clip_gradients=None):
super(Estimator, self).__init__(model_dir=model_dir)
learning_rate=0.1,
optimizer='Adagrad',
clip_gradients=None,
config=None):
super(Estimator, self).__init__(model_dir=model_dir, config=config)
self._model_fn = model_fn
self._classification = classification
@ -486,12 +544,25 @@ class Estimator(BaseEstimator):
Tuple of train `Operation` and loss `Tensor`.
"""
_, loss = self._model_fn(features, targets, ModeKeys.TRAIN)
# TODO(ipolosukhin): Move this to TensorFlowEstimator when
# moving out training.
if isinstance(self.learning_rate, types.FunctionType):
learning_rate = self.learning_rate(contrib_framework.get_global_step())
else:
learning_rate = self.learning_rate
if isinstance(self.optimizer, types.FunctionType):
optimizer = self.optimizer(learning_rate)
else:
optimizer = self.optimizer
train_op = layers.optimize_loss(
loss,
contrib_framework.get_global_step(),
learning_rate=self.learning_rate,
optimizer=self.optimizer,
learning_rate=learning_rate,
optimizer=optimizer,
clip_gradients=self.clip_gradients)
# Add update ops.
train_op = control_flow_ops.group(
train_op, *ops.get_collection('update_ops'))
return train_op, loss
def _get_eval_ops(self, features, targets, metrics):

View File

@ -37,6 +37,24 @@ def linear_model_fn(features, target, unused_mode):
return tf.contrib.learn.models.linear_regression_zero_init(features, target)
class CheckCallsMonitor(tf.contrib.learn.monitors.BaseMonitor):
def __init__(self):
self.calls = None
self.expect_calls = None
def begin(self, max_steps):
self.calls = 0
self.expect_calls = max_steps
def step_end(self, step, outputs):
self.calls += 1
return False
def end(self):
assert self.calls == self.expect_calls
class EstimatorTest(tf.test.TestCase):
def testTrain(self):
@ -64,6 +82,12 @@ class EstimatorTest(tf.test.TestCase):
with self.assertRaises(ValueError):
est.train(input_fn=other_input_fn, steps=1)
def testMonitors(self):
est = tf.contrib.learn.Estimator(model_fn=linear_model_fn,
classification=False)
est.train(input_fn=boston_input_fn, steps=21,
monitors=[CheckCallsMonitor()])
if __name__ == '__main__':
tf.test.main()

View File

@ -16,11 +16,151 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from tensorflow.contrib.learn.python.learn.estimators import _sklearn
from tensorflow.contrib.learn.python.learn.estimators.base import TensorFlowEstimator
from tensorflow.contrib import layers
from tensorflow.contrib.learn.python.learn import models
from tensorflow.contrib.learn.python.learn.estimators import _sklearn
from tensorflow.contrib.learn.python.learn.estimators import dnn_linear_combined
from tensorflow.contrib.learn.python.learn.estimators.base import TensorFlowEstimator
class LinearClassifier(dnn_linear_combined.DNNLinearCombinedClassifier):
"""Linear classifier model.
Example:
```
installed_app_id = sparse_column_with_hash_bucket("installed_id", 1e6)
impression_app_id = sparse_column_with_hash_bucket("impression_id", 1e6)
installed_x_impression = crossed_column(
[installed_app_id, impression_app_id])
estimator = LinearClassifier(
feature_columns=[impression_app_id, installed_x_impression])
# Input builders
def input_fn_train: # returns X, Y
...
def input_fn_eval: # returns X, Y
...
estimator.train(input_fn_train)
estimator.evaluate(input_fn_eval)
estimator.predict(x)
```
Input of `fit`, `train`, and `evaluate` should have following features,
otherwise there will be a `KeyError`:
if `weight_column_name` is not `None`, a feature with
`key=weight_column_name` whose value is a `Tensor`.
for each `column` in `feature_columns`:
- if `column` is a `SparseColumn`, a feature with `key=column.name`
whose `value` is a `SparseTensor`.
- if `column` is a `RealValuedColumn, a feature with `key=column.name`
whose `value` is a `Tensor`.
- if `feauture_columns` is None, then `input` must contains only real
valued `Tensor`.
Parameters:
feature_columns: An iterable containing all the feature columns used by the
model. All items in the set should be instances of classes derived from
`FeatureColumn`.
model_dir: Directory to save model parameters, graph and etc.
n_classes: number of target classes. Default is binary classification.
weight_column_name: A string defining feature column name representing
weights. It is used to down weight or boost examples during training. It
will be multiplied by the loss of the example.
optimizer: An instance of `tf.Optimizer` used to train the model. If `None`,
will use an Ftrl optimizer.
"""
def __init__(self,
feature_columns=None,
model_dir=None,
n_classes=2,
weight_column_name=None,
optimizer=None):
super(LinearClassifier, self).__init__(
model_dir=model_dir,
n_classes=n_classes,
weight_column_name=weight_column_name,
linear_feature_columns=feature_columns,
linear_optimizer=optimizer)
def _get_train_ops(self, features, targets):
"""See base class."""
if self._linear_feature_columns is None:
self._linear_feature_columns = layers.infer_real_valued_columns(features)
return super(LinearClassifier, self)._get_train_ops(features, targets)
class LinearRegressor(dnn_linear_combined.DNNLinearCombinedRegressor):
"""Linear regressor model.
Example:
```
installed_app_id = sparse_column_with_hash_bucket("installed_id", 1e6)
impression_app_id = sparse_column_with_hash_bucket("impression_id", 1e6)
installed_x_impression = crossed_column(
[installed_app_id, impression_app_id])
estimator = LinearRegressor(
feature_columns=[impression_app_id, installed_x_impression])
# Input builders
def input_fn_train: # returns X, Y
...
def input_fn_eval: # returns X, Y
...
estimator.train(input_fn_train)
estimator.evaluate(input_fn_eval)
estimator.predict(x)
```
Input of `fit`, `train`, and `evaluate` should have following features,
otherwise there will be a KeyError:
if `weight_column_name` is not None:
key=weight_column_name, value=a `Tensor`
for column in `feature_columns`:
- if isinstance(column, `SparseColumn`):
key=column.name, value=a `SparseTensor`
- if isinstance(column, `RealValuedColumn`):
key=column.name, value=a `Tensor`
- if `feauture_columns` is None:
input must contains only real valued `Tensor`.
Parameters:
feature_columns: An iterable containing all the feature columns used by the
model. All items in the set should be instances of classes derived from
`FeatureColumn`.
model_dir: Directory to save model parameters, graph and etc.
weight_column_name: A string defining feature column name representing
weights. It is used to down weight or boost examples during training. It
will be multiplied by the loss of the example.
optimizer: An instance of `tf.Optimizer` used to train the model. If `None`,
will use an Ftrl optimizer.
"""
def __init__(self,
feature_columns=None,
model_dir=None,
n_classes=2,
weight_column_name=None,
optimizer=None):
super(LinearRegressor, self).__init__(
model_dir=model_dir,
weight_column_name=weight_column_name,
linear_feature_columns=feature_columns,
linear_optimizer=optimizer)
def _get_train_ops(self, features, targets):
"""See base class."""
if self._linear_feature_columns is None:
self._linear_feature_columns = layers.infer_real_valued_columns(features)
return super(LinearRegressor, self)._get_train_ops(features, targets)
# TODO(ipolosukhin): Deprecate this class in favor of LinearClassifier.
class TensorFlowLinearRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
"""TensorFlow Linear Regression model."""
@ -50,12 +190,12 @@ class TensorFlowLinearRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@property
def weights_(self):
"""Returns weights of the linear regression."""
return self.get_tensor_value('linear_regression/weights:0')
return self.get_tensor_value('linear_regression/weights')
@property
def bias_(self):
"""Returns bias of the linear regression."""
return self.get_tensor_value('linear_regression/bias:0')
return self.get_tensor_value('linear_regression/bias')
class TensorFlowLinearClassifier(TensorFlowEstimator, _sklearn.ClassifierMixin):
@ -89,12 +229,12 @@ class TensorFlowLinearClassifier(TensorFlowEstimator, _sklearn.ClassifierMixin):
@property
def weights_(self):
"""Returns weights of the linear classifier."""
return self.get_tensor_value('logistic_regression/weights:0')
return self.get_tensor_value('logistic_regression/weights')
@property
def bias_(self):
"""Returns weights of the linear classifier."""
return self.get_tensor_value('logistic_regression/bias:0')
return self.get_tensor_value('logistic_regression/bias')
TensorFlowRegressor = TensorFlowLinearRegressor

View File

@ -0,0 +1,155 @@
# Copyright 2015 Google Inc. 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 estimators.linear."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow as tf
class LinearClassifierTest(tf.test.TestCase):
def testTrain(self):
"""Tests that loss goes down with training."""
def input_fn():
return {
'age': tf.constant([1]),
'language': tf.SparseTensor(values=['english'],
indices=[[0, 0]],
shape=[1, 1])
}, tf.constant([[1.]])
language = tf.contrib.layers.sparse_column_with_hash_bucket('language', 100)
age = tf.contrib.layers.real_valued_column('age')
classifier = tf.contrib.learn.LinearClassifier(
feature_columns=[age, language])
loss1 = classifier.train(input_fn, steps=100)
loss2 = classifier.train(input_fn, steps=200)
self.assertLess(loss2, loss1)
self.assertLess(loss2, 0.01)
def testTrainOptimizerWithL1Reg(self):
"""Tests l1 regularized model has higher loss."""
def input_fn():
return {
'language': tf.SparseTensor(values=['hindi'],
indices=[[0, 0]],
shape=[1, 1])
}, tf.constant([[1.]])
language = tf.contrib.layers.sparse_column_with_hash_bucket('language', 100)
classifier_no_reg = tf.contrib.learn.LinearClassifier(
feature_columns=[language])
classifier_with_reg = tf.contrib.learn.LinearClassifier(
feature_columns=[language],
optimizer=tf.train.FtrlOptimizer(learning_rate=1.0,
l1_regularization_strength=100.))
loss_no_reg = classifier_no_reg.train(input_fn, steps=100)
loss_with_reg = classifier_with_reg.train(input_fn, steps=100)
self.assertLess(loss_no_reg, loss_with_reg)
def testTrainWithMissingFeature(self):
"""Tests that training works with missing features."""
def input_fn():
return {
'language': tf.SparseTensor(values=['Swahili', 'turkish'],
indices=[[0, 0], [2, 0]],
shape=[3, 1])
}, tf.constant([[1.], [1.], [1.]])
language = tf.contrib.layers.sparse_column_with_hash_bucket('language', 100)
classifier = tf.contrib.learn.LinearClassifier(feature_columns=[language])
loss = classifier.train(input_fn, steps=100)
self.assertLess(loss, 0.01)
def testEval(self):
"""Tests that eval produces correct metrics.
"""
def input_fn():
return {
'age': tf.constant([[1], [2]]),
'language': tf.SparseTensor(values=['greek', 'chinise'],
indices=[[0, 0], [1, 0]],
shape=[2, 1]),
}, tf.constant([[1.], [0.]])
language = tf.contrib.layers.sparse_column_with_hash_bucket('language', 100)
age = tf.contrib.layers.real_valued_column('age')
classifier = tf.contrib.learn.LinearClassifier(
feature_columns=[age, language])
# Evaluate on untrained model
classifier.evaluate(input_fn=input_fn, steps=2)
# TODO(ispir): Enable accuracy check after resolving the randomness issue.
# self.assertAlmostEqual(.5, evaluated_values['accuracy/mean'])
# Evaluate on trained mdoel
classifier.train(input_fn, steps=100)
classifier.evaluate(input_fn=input_fn, steps=2)
# TODO(ispir): Enable accuracy check after resolving the randomness issue.
# self.assertLess(evaluated_values['loss/mean'], 0.3)
# self.assertGreater(evaluated_values['accuracy/mean'], .95)
class LinearRegressorTest(tf.test.TestCase):
def testRegression(self):
"""Tests that loss goes down with training."""
def input_fn():
return {
'age': tf.constant([1]),
'language': tf.SparseTensor(values=['english'],
indices=[[0, 0]],
shape=[1, 1])
}, tf.constant([[10.]])
language = tf.contrib.layers.sparse_column_with_hash_bucket('language', 100)
age = tf.contrib.layers.real_valued_column('age')
classifier = tf.contrib.learn.LinearRegressor(
feature_columns=[age, language])
loss1 = classifier.train(input_fn, steps=100)
loss2 = classifier.train(input_fn, steps=200)
self.assertLess(loss2, loss1)
self.assertLess(loss2, 0.01)
def boston_input_fn():
boston = tf.contrib.learn.datasets.load_boston()
features = tf.cast(tf.reshape(tf.constant(boston.data), [-1, 13]), tf.float32)
target = tf.cast(tf.reshape(tf.constant(boston.target), [-1, 1]), tf.float32)
return features, target
class InferedColumnTest(tf.test.TestCase):
def testTrain(self):
est = tf.contrib.learn.LinearRegressor()
est.train(input_fn=boston_input_fn, steps=1)
_ = est.evaluate(input_fn=boston_input_fn, steps=1)
if __name__ == '__main__':
tf.test.main()

View File

@ -111,12 +111,12 @@ class TensorFlowRNNClassifier(TensorFlowEstimator, _sklearn.ClassifierMixin):
@property
def bias_(self):
"""Returns bias of the rnn layer."""
return self.get_tensor_value('logistic_regression/bias:0')
return self.get_tensor_value('logistic_regression/bias')
@property
def weights_(self):
"""Returns weights of the rnn layer."""
return self.get_tensor_value('logistic_regression/weights:0')
return self.get_tensor_value('logistic_regression/weights')
class TensorFlowRNNRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@ -201,9 +201,9 @@ class TensorFlowRNNRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@property
def bias_(self):
"""Returns bias of the rnn layer."""
return self.get_tensor_value('linear_regression/bias:0')
return self.get_tensor_value('linear_regression/bias')
@property
def weights_(self):
"""Returns weights of the rnn layer."""
return self.get_tensor_value('linear_regression/weights:0')
return self.get_tensor_value('linear_regression/weights')

View File

@ -28,12 +28,14 @@ from six import reraise
from tensorflow.contrib.framework.python.ops import ops as contrib_ops
from tensorflow.contrib.framework.python.ops import variables as contrib_variables
from tensorflow.contrib.layers.python.layers import summaries
from tensorflow.contrib.learn.python.learn import monitors as monitors_lib
from tensorflow.core.util.event_pb2 import SessionLog
from tensorflow.python.client import session as tf_session
from tensorflow.python.framework import errors
from tensorflow.python.framework import ops
from tensorflow.python.framework import tensor_util
from tensorflow.python.ops import data_flow_ops
from tensorflow.python.ops import logging_ops
from tensorflow.python.ops import variables
from tensorflow.python.platform import gfile
from tensorflow.python.platform import tf_logging as logging
@ -98,23 +100,24 @@ def _prepare_session(graph,
start_services,
global_step_tensor,
init_op=None,
init_feed_dict=None,
init_fn=None,
supervisor_is_chief=True,
supervisor_master='',
supervisor_save_model_secs=600,
supervisor_save_summaries_secs=10):
supervisor_save_model_secs=600):
"""Starts a session using the supervisor."""
if global_step_tensor is None:
global_step_tensor = Supervisor.USE_DEFAULT
supervisor = Supervisor(
graph,
init_op=init_op or Supervisor.USE_DEFAULT,
init_feed_dict=init_feed_dict,
is_chief=supervisor_is_chief,
logdir=output_dir,
saver=_make_saver(graph),
global_step=global_step_tensor,
summary_op=None,
save_model_secs=supervisor_save_model_secs,
save_summaries_secs=supervisor_save_summaries_secs,
init_fn=init_fn)
session = supervisor.PrepareSession(master=supervisor_master,
start_standard_services=start_services)
@ -122,6 +125,23 @@ def _prepare_session(graph,
return supervisor, session
def _run_with_monitors(session, step, tensors, feed_dict, monitors):
"""Runs session for given tensors with monitor callbacks."""
for monitor in monitors:
tensors = monitor.step_begin(step, tensors)
outputs = session.run(tensors, feed_dict=feed_dict)
outputs = dict(zip(
[t.name if isinstance(t, ops.Tensor) else t for t in tensors],
outputs))
should_stop = False
for monitor in monitors:
induce_stop = monitor.step_end(step, outputs)
should_stop = should_stop or induce_stop
return outputs, should_stop
# TODO(ptucker): Add unit test.
# TODO(wicke): switch to forced named kwargs
def train(graph,
@ -130,15 +150,17 @@ def train(graph,
loss_op,
global_step_tensor=None,
init_op=None,
init_feed_dict=None,
init_fn=None,
log_every_steps=10,
supervisor_is_chief=True,
supervisor_master='',
supervisor_save_model_secs=600,
supervisor_save_summaries_secs=10,
supervisor_save_summaries_steps=100,
feed_fn=None,
max_steps=None,
fail_on_nan_loss=True):
fail_on_nan_loss=True,
monitors=None):
"""Train a model.
Given `graph`, a directory to write outputs to (`output_dir`), and some ops,
@ -164,6 +186,8 @@ def train(graph,
one is extracted from the graph using the same logic as in `Supervisor`.
init_op: An op that initializes the graph. If `None`, use `Supervisor`'s
default.
init_feed_dict: A dictionary that maps `Tensor` objects to feed values.
This feed dictionary will be used when `init_op` is evaluated.
init_fn: Optional callable passed to Supervisor to initialize the model.
log_every_steps: Output logs regularly. The logs contain timing data and the
current loss.
@ -172,13 +196,15 @@ def train(graph,
supervisor_master: The master string to use when preparing the session.
supervisor_save_model_secs: Save a checkpoint every
`supervisor_save_model_secs` seconds when training.
supervisor_save_summaries_secs: Save summaries every
`supervisor_save_summaries_secs` seconds when training.
supervisor_save_summaries_steps: Save summaries every
`supervisor_save_summaries_steps` seconds when training.
feed_fn: A function that is called every iteration to produce a `feed_dict`
passed to `session.run` calls. Optional.
max_steps: Train until `global_step_tensor` evaluates to this value.
fail_on_nan_loss: If true, raise `NanLossDuringTrainingError` if `loss_op`
evaluates to `NaN`. If false, continue training as if nothing happened.
monitors: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
Returns:
The final loss value.
@ -194,17 +220,30 @@ def train(graph,
graph, global_step_tensor)
if global_step_tensor is None:
raise ValueError('No "global_step" was provided or found in the graph.')
# TODO(ipolosukhin): Replace all functionality of Supervisor with Monitors.
if not monitors:
monitors = monitors_lib.get_default_monitors(
loss_op=loss_op,
summary_op=logging_ops.get_summary_op(),
save_summary_steps=supervisor_save_summaries_steps,
output_dir=output_dir)
# Start monitors, can create graph parts.
for monitor in monitors:
monitor.begin(max_steps=max_steps)
supervisor, session = _prepare_session(
graph=graph,
output_dir=output_dir,
start_services=True,
global_step_tensor=global_step_tensor,
init_op=init_op,
init_feed_dict=init_feed_dict,
init_fn=init_fn,
supervisor_is_chief=supervisor_is_chief,
supervisor_master=supervisor_master,
supervisor_save_model_secs=supervisor_save_model_secs,
supervisor_save_summaries_secs=supervisor_save_summaries_secs)
supervisor_save_model_secs=supervisor_save_model_secs)
with session:
get_current_step = lambda: session.run(global_step_tensor)
@ -215,13 +254,18 @@ def train(graph,
loss_value = None
logging.info('Training steps [%d,%s)', last_step, 'inf'
if max_steps is None else str(max_steps))
excinfo = None
try:
while not supervisor.ShouldStop() and (
(max_steps is None) or (last_step < max_steps)):
start_time = time.time()
feed_dict = feed_fn() if feed_fn is not None else None
_, loss_value = session.run([train_op, loss_op], feed_dict=feed_dict)
outputs, should_stop = _run_with_monitors(
session, last_step + 1, [train_op, loss_op], feed_dict, monitors)
loss_value = outputs[loss_op.name]
if np.isnan(loss_value):
failure_message = 'Model diverged with loss = NaN.'
if fail_on_nan_loss:
@ -230,6 +274,9 @@ def train(graph,
else:
logging.warning(failure_message)
if should_stop:
break
this_step = get_current_step()
if this_step <= last_step:
@ -268,12 +315,11 @@ def train(graph,
logging.info('Saving checkpoint for step %d to checkpoint: %s.' % (
last_step, ckpt_path))
supervisor.saver.save(session, ckpt_path, global_step=last_step)
if supervisor.summary_op is not None:
summary_strs = session.run(supervisor.summary_op)
supervisor.summary_writer.add_summary(summary_strs, last_step)
supervisor.summary_writer.add_session_log(
SessionLog(status=SessionLog.STOP), last_step)
supervisor.summary_writer.close()
# Finish monitors.
for monitor in monitors:
monitor.end()
# catch OutOfRangeError which is thrown when queue is out of data (and for
# other reasons as well).
except errors.OutOfRangeError as e:
@ -354,6 +400,9 @@ def evaluate(graph,
if isinstance(value, ops.Tensor):
summaries.summarize_tensor(value, tag=key)
# Create or get summary op.
summary_op = logging_ops.get_summary_op()
# TODO(wicke): Don't use supervisor here, or switch to output_dir=eval_dir.
supervisor, session = _prepare_session(
graph=graph,
@ -363,8 +412,7 @@ def evaluate(graph,
init_op=init_op,
supervisor_is_chief=True,
supervisor_master=supervisor_master,
supervisor_save_model_secs=None,
supervisor_save_summaries_secs=None)
supervisor_save_model_secs=None)
global_step_tensor = supervisor.global_step
with session:
@ -394,14 +442,17 @@ def evaluate(graph,
', '.join('%s = %s' % (k, v)
for k, v in eval_results.items()))
finally:
# Make our own summary writer and write a summary to the eval dir
if supervisor.summary_op is not None:
# Make our own summary writer and write a summary to the eval dir.
# Only is feed_fn is not provided.
# TODO(ipolosukhin): Convert evaluation to use streaming_metrics,
# then we can save for non feed_fn as well.
if summary_op is not None and feed_fn is None:
summary_writer = None
try:
summary_writer = SummaryWriter(output_dir,
graph_def=session.graph_def)
summary_str = session.run(supervisor.summary_op)
summary_str = session.run(summary_op)
if summary_str:
summary_writer.add_summary(summary_str, current_global_step)
finally:
@ -414,7 +465,10 @@ def evaluate(graph,
# catch OutOfRangeError which is thrown when queue is out of data (and for
# other reasons as well).
except errors.OutOfRangeError as e:
logging.warn('Input queue exhausted: %s.', e)
logging.warn('Input queue is exhausted: %s.', e)
# catch StopIteration which is thrown is DataReader is out of data.
except StopIteration as e:
logging.info('Input iterator is exhausted: %s.', e)
return eval_results, current_global_step

View File

@ -13,6 +13,9 @@
# 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.
# TODO(ipolosukhin): Replace this module with feed-dict queue runners & queues.
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
@ -33,6 +36,8 @@ from .dask_io import HAS_DASK, extract_dask_data, extract_dask_labels
def _get_in_out_shape(x_shape, y_shape, n_classes, batch_size):
"""Returns shape for input and output of the data feeder."""
if batch_size < 0:
batch_size = x_shape[0]
x_shape = list(x_shape[1:]) if len(x_shape) > 1 else [1]
input_shape = [batch_size] + x_shape
if y_shape is None:
@ -65,7 +70,8 @@ def _is_iterable(X):
return hasattr(X, 'next') or hasattr(X, '__next__')
def setup_train_data_feeder(X, y, n_classes, batch_size):
def setup_train_data_feeder(
X, y, n_classes, batch_size, shuffle=True, epochs=None):
"""Create data feeder, to sample inputs from dataset.
If X and y are iterators, use StreamingDataFeeder.
@ -95,7 +101,8 @@ def setup_train_data_feeder(X, y, n_classes, batch_size):
raise ValueError('Both X and y should be iterators for '
'streaming learning to work.')
data_feeder_cls = StreamingDataFeeder
return data_feeder_cls(X, y, n_classes, batch_size)
return data_feeder_cls(
X, y, n_classes, batch_size, shuffle=shuffle, epochs=epochs)
def _batch_data(X, batch_size):
@ -189,7 +196,7 @@ class DataFeeder(object):
output_dtype: dtype of output.
"""
def __init__(self, X, y, n_classes, batch_size, random_state=None):
def __init__(self, X, y, n_classes, batch_size, shuffle=True, random_state=None, epochs=None):
x_dtype = np.int64 if X.dtype == np.int64 else np.float32
y_dtype = (
np.int64 if n_classes is not None and n_classes > 1 else np.float32)
@ -201,6 +208,7 @@ class DataFeeder(object):
self.y = y
self.n_classes = n_classes
self.batch_size = batch_size
self.max_epochs = epochs
self.input_shape, self.output_shape = _get_in_out_shape(self.X.shape, None
if self.y is None
else self.y.shape,
@ -213,9 +221,13 @@ class DataFeeder(object):
self.output_dtype = np.float32
else:
self.output_dtype = y.dtype
self.shuffle = shuffle
self.random_state = np.random.RandomState(
42) if random_state is None else random_state
self.indices = self.random_state.permutation(self.X.shape[0])
if self.shuffle:
self.indices = self.random_state.permutation(self.X.shape[0])
else:
self.indices = np.array(range(self.X.shape[0]))
self.offset = 0
self.epoch = 0
self._epoch_placeholder = None
@ -283,16 +295,19 @@ class DataFeeder(object):
from X and y.
"""
def _feed_dict_fn():
if self.max_epochs is not None and self.epoch + 1 > self.max_epochs:
raise StopIteration
assert self._input_placeholder != None
feed_dict = {}
if self._epoch_placeholder is not None:
feed_dict[self._epoch_placeholder.name] = [self.epoch]
# take random indices
# take next batch of indices
if self.batch_size < 0:
batch_indices = self.indices
else:
batch_indices = self.indices[self.offset:self.offset + self.batch_size]
end = min(self.X.shape[0], self.offset + self.batch_size)
batch_indices = self.indices[self.offset:end]
# assign input features from random indices
inp = np.array(self.X[batch_indices]).reshape((batch_indices.shape[0], 1)) \
@ -300,10 +315,13 @@ class DataFeeder(object):
feed_dict[self._input_placeholder.name] = inp
# move offset and reset it if necessary
self.offset += self.batch_size
if self.offset >= self.X.shape[0]:
self.indices = self.random_state.permutation(self.X.shape[0])
self.offset = 0
if self.batch_size > 0:
self.offset += self.batch_size
if self.offset >= self.X.shape[0]:
self.indices = self.random_state.permutation(self.X.shape[0])
self.offset = 0
self.epoch += 1
else:
self.epoch += 1
# return early if there are no labels
@ -359,15 +377,21 @@ class StreamingDataFeeder(DataFeeder):
output_dtype: dtype of output.
"""
def __init__(self, X, y, n_classes, batch_size):
def __init__(self, X, y, n_classes, batch_size, shuffle=False, epochs=None):
X_first_el = six.next(X)
y_first_el = six.next(y)
self.X = itertools.chain([X_first_el], X)
self.y = itertools.chain([y_first_el], y)
if y is not None:
y_first_el = six.next(y)
self.y = itertools.chain([y_first_el], y)
else:
y_first_el = None
self.y = None
self.n_classes = n_classes
self.batch_size = batch_size
self.input_shape, self.output_shape = _get_in_out_shape(
[1] + list(X_first_el.shape), [1] + list(y_first_el.shape), n_classes,
[1] + list(X_first_el.shape),
[1] + list(y_first_el.shape) if y is not None else None,
n_classes,
batch_size)
self.input_dtype = X_first_el.dtype
# Convert float64 to float32, as all the parameters in the model are
@ -396,21 +420,37 @@ class StreamingDataFeeder(DataFeeder):
A function that when called samples a random subset of batch size
from X and y.
"""
self.stopped = False
def _feed_dict_fn():
if self.stopped:
raise StopIteration
inp = np.zeros(self.input_shape, dtype=self.input_dtype)
out = np.zeros(self.output_shape, dtype=self.output_dtype)
if self.y is not None:
out = np.zeros(self.output_shape, dtype=self.output_dtype)
for i in xrange(self.batch_size):
inp[i, :] = six.next(self.X)
y = six.next(self.y)
if self.n_classes > 1:
if len(self.output_shape) == 2:
out.itemset((i, y), 1.0)
# Add handling when queue ends.
try:
inp[i, :] = six.next(self.X)
except StopIteration:
self.stopped = True
inp = inp[:i, :]
if self.y is not None:
out = out[:i]
break
if self.y is not None:
y = six.next(self.y)
if self.n_classes > 1:
if len(self.output_shape) == 2:
out.itemset((i, y), 1.0)
else:
for idx, value in enumerate(y):
out.itemset(tuple([i, idx, value]), 1.0)
else:
for idx, value in enumerate(y):
out.itemset(tuple([i, idx, value]), 1.0)
else:
out[i] = y
out[i] = y
if self.y is None:
return {self._input_placeholder.name: inp}
return {self._input_placeholder.name: inp,
self._output_placeholder.name: out}
@ -443,7 +483,7 @@ class DaskDataFeeder(object):
input_dtype: dtype of input.
output_dtype: dtype of output.
"""
def __init__(self, X, y, n_classes, batch_size, random_state=None):
def __init__(self, X, y, n_classes, batch_size, shuffle=True, random_state=None):
import dask.dataframe as dd
# TODO(terrytangyuan): check X and y dtypes in dask_io like pandas
self.X = X

View File

@ -17,221 +17,199 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import sys
import numpy as np
from tensorflow.core.framework import summary_pb2
from tensorflow.python.training import training as train
from tensorflow.contrib.learn.python.learn.io.data_feeder import setup_train_data_feeder
# pylint: disable=too-many-instance-attributes
# pylint: disable=too-few-public-methods
# pylint: disable=too-many-arguments
# pylint: disable=attribute-defined-outside-init
def default_monitor(verbose=1):
"""Returns very simple monitor object to summarize training progress.
Args:
verbose: Level of verbosity of output.
Returns:
Default monitor object.
"""
return BaseMonitor(verbose=verbose)
from tensorflow.python.platform import tf_logging as logging
from tensorflow.python.training import summary_io
class BaseMonitor(object):
"""Base class for all learning monitors.
Stores and reports training loss throughout learning
Parameters:
print_steps: Number of steps in between printing cost.
early_stopping_rounds: Activates early stopping if this is not None.
Loss needs to decrease at least every
<early_stopping_rounds>
round(s) to continue training. (default: None)
verbose: Level of verbosity of output.
"""Base class for Monitors.
Defines basic interfaces of Monitors.
"""
def __init__(self, print_steps=100, early_stopping_rounds=None, verbose=1):
self.print_steps = print_steps
self.early_stopping_rounds = early_stopping_rounds
self.converged = False
self.min_loss = np.inf
self.min_loss_i = 0
self.last_loss_seen = np.inf
self.steps = 0
self.print_train_loss_buffer = []
self.all_train_loss_buffer = []
self.verbose = verbose
self.epoch = None
def update(self, global_step, step_number, training_loss, sess,
feed_params_fn, loss_expression_tensor):
"""Adds training_loss to monitor.
Triggers printed output if appropriate
Args:
global_step: global step number
step_number: current step in training
training_loss: float value of training loss
sess: session for computation (used to calculate validation loss)
feed_params_fn: function generating dict with information like
epoch. Sometimes None.
loss_expression_tensor: Tensor applied to validation data to
calculate val loss
"""
self.steps = step_number
self.global_step = global_step
self.print_train_loss_buffer.append(training_loss)
self.all_train_loss_buffer.append(training_loss)
self.sess = sess
self.loss_expression_tensor = loss_expression_tensor
self._set_last_loss_seen()
if self.last_loss_seen < self.min_loss:
self.min_loss = self.last_loss_seen
self.min_loss_i = self.steps
self._set_epoch(feed_params_fn)
self.report()
def _set_last_loss_seen(self):
"""Sets last_loss_seen attribute to most recent training error."""
self.last_loss_seen = self.all_train_loss_buffer[-1]
self._estimator = None
def report(self):
"""Checks whether to report, and prints loss information if appropriate."""
if self.verbose and (self.steps % self.print_steps == 0):
self._set_training_summary()
print(self._summary_str)
def set_estimator(self, estimator):
self._estimator = estimator
def monitor_inducing_stop(self):
"""Returns True if the monitor requests the model stop.
Returns:
True if the monitor requests the model stop (e.g. for early stopping).
"""
if self.early_stopping_rounds is None:
return False
stop_now = (self.steps - self.min_loss_i >= self.early_stopping_rounds)
if stop_now:
sys.stderr.write("Stopping. Best step:\n step {} with loss {}\n"
.format(self.min_loss_i, self.min_loss))
return stop_now
def create_val_feed_dict(self, inp, out):
"""Validation requires access to TensorFlow placeholders.
Not used in this Monitor
def begin(self, max_steps=None):
"""Callback at the beginning of training/evaluation.
Args:
inp: not used
out: not used
max_steps: Maximum steps this training will run until.
"""
pass
def _set_epoch(self, feed_params_fn):
"""Sets self.epoch from a function providing this info in a dict."""
if feed_params_fn:
feed_params = feed_params_fn()
self.epoch = feed_params["epoch"] if "epoch" in feed_params else None
def _set_training_summary(self):
"""Returns the string to be written describing training progress"""
avg_train_loss = np.mean(self.print_train_loss_buffer)
self.print_train_loss_buffer = []
if self.epoch:
self._summary_str = (
"Step #{step}, epoch #{epoch}, avg. train loss: {loss:.5f}"
.format(step=self.steps,
loss=avg_train_loss,
epoch=self.epoch))
else:
self._summary_str = ("Step #{step}, avg. train loss: {loss:.5f}"
.format(step=self.global_step,
loss=avg_train_loss))
self._modify_summary_string()
def _modify_summary_string(self):
"""Makes monitor specific changes to printed summary.
Nothing interesting in BaseMonitor
"""
def end(self):
"""Callback at the end of training/evaluation."""
pass
def epoch_begin(self, epoch):
pass
class ValidationMonitor(BaseMonitor):
"""Monitor that reports validation score and uses it for early stopping.
def epoch_end(self, epoch):
pass
def step_begin(self, step, tensors): # pylint: disable=unused-argument
"""Callback before training step begins.
Use this callback to:
- override which tensors to run.
Args:
step: int, global step of the model.
tensors: list of `Tensors` that going to be passed to session.run.
Returns:
Dict of `Tensors` that going to be ran.
"""
return tensors
def step_end(self, step, output): # pylint: disable=unused-argument
"""Callback after training step finished.
Use this callback to:
- log results.
- save checkpoints.
- compute validation score.
- perform early stopping.
Args:
step: `int`, global step of the model.
output: `dict` of `np.array` results executed.
Returns:
`bool`, `True` if model should stop, `False` or `None` if continue.
"""
return False
class EveryN(BaseMonitor):
"""Base class for monitors that execute callbacks every n steps / seconds.
Parameters:
val_X: Validation features
val_y: Validation labels
n_classes: Number of labels in output. 0 for regression
print_steps: Number of steps in between printing cost.
early_stopping_rounds: Activates early stopping if this is not None.
Loss needs to decrease at least every
<early_stopping_rounds>
round(s) to continue training. (default: None)
every_n_steps: int, calls `every_n_step_{begin,end}` every this many steps.
first_n_steps: int, calls `every_n_step_{begin,end}` for first n steps.
TODO(ipolosukhin): Add also every n seconds.
"""
def __init__(self,
val_X,
val_y,
n_classes=0,
print_steps=100,
early_stopping_rounds=None):
super(ValidationMonitor, self).__init__(
print_steps=print_steps,
early_stopping_rounds=early_stopping_rounds)
self.val_feeder = setup_train_data_feeder(val_X, val_y, n_classes, -1)
self.print_val_loss_buffer = []
self.all_val_loss_buffer = []
self._summary_writer = None
def __init__(
self, every_n_steps=100, first_n_steps=1):
self._every_n_steps = every_n_steps
self._first_n_steps = first_n_steps
self._max_steps = None
def create_val_feed_dict(self, inp, out):
"""Set tensorflow placeholders and create validation data feed."""
self.val_feeder.set_placeholders(inp, out)
self.val_dict = self.val_feeder.get_feed_dict_fn()()
def begin(self, max_steps=None):
self._max_steps = max_steps
def every_n_step_begin(self, step, tensors): # pylint: disable=unused-argument
return tensors
def every_n_step_end(self, step, outputs): # pylint: disable=unused-argument
return False
def step_begin(self, step, tensors):
if (step <= self._first_n_steps or step % self._every_n_steps == 0 or
step == self._max_steps):
tensors = self.every_n_step_begin(step, tensors)
return tensors
def step_end(self, step, output):
to_stop = False
if (step <= self._first_n_steps or step % self._every_n_steps == 0 or
step == self._max_steps):
to_stop = self.every_n_step_end(step, output)
return to_stop
class PrintTensor(EveryN):
def __init__(self, tensor_names, every_n=100, first_n=1):
super(PrintTensor, self).__init__(every_n, first_n)
self._tensor_names = tensor_names
def every_n_step_begin(self, unused_step, tensors):
return tensors + self._tensor_names
def every_n_step_end(self, step, outputs):
stats = []
for name in self._tensor_names:
if name in outputs:
stats.append("%s = %s" % (name, str(outputs[name])))
logging.info("Step %d: %s" % (step, ", ".join(stats)))
class SummarySaver(EveryN):
"""Saves summary every N seconds."""
def __init__(self, summary_op, save_steps=100, output_dir=None):
# TODO(ipolosukhin): Implement every N seconds.
super(SummarySaver, self).__init__(every_n_steps=save_steps)
self._summary_op = summary_op
self._summary_writer = None
if output_dir:
self._summary_writer = summary_io.SummaryWriter(output_dir)
def set_estimator(self, estimator):
super(ValidationMonitor, self).set_estimator(estimator)
if estimator._output_dir is None:
return
self._summary_writer = train.SummaryWriter(os.path.join(estimator._output_dir, 'eval'))
super(SummarySaver, self).set_estimator(estimator)
self._summary_writer = summary_io.SummaryWriter(self._estimator.model_dir)
def _set_last_loss_seen(self):
"""Sets self.last_loss_seen to most recent validation loss.
def every_n_step_begin(self, unused_step, tensors):
return tensors + [self._summary_op]
Also stores this value to appropriate buffers
"""
[val_loss] = self.sess.run(
[self.loss_expression_tensor],
feed_dict=self.val_dict)
self.last_loss_seen = val_loss
self.all_val_loss_buffer.append(val_loss)
self.print_val_loss_buffer.append(val_loss)
if self._summary_writer is not None:
summary = summary_pb2.Summary()
value = summary.value.add()
value.tag = "loss"
value.simple_value = float(val_loss)
self._summary_writer.add_summary(summary, self.global_step)
def every_n_step_end(self, step, outputs):
summary_strs = outputs[self._summary_op.name]
if self._summary_writer:
self._summary_writer.add_summary(summary_strs, step)
return False
def _modify_summary_string(self):
"""Flushes validation print buffer into summary string."""
avg_val_loss = np.mean(self.print_val_loss_buffer)
self.print_val_loss_buffer = []
val_loss_string = "avg. val loss: {val_loss:.5f}".format(
val_loss=avg_val_loss)
self._summary_str = (", ".join([self._summary_str, val_loss_string]))
def end(self):
self._summary_writer.flush()
class ValidationMonitor(EveryN):
"""Runs evaluation every n steps.
Can do early stopping on validation loss if `early_stopping_rounds` provided.
"""
def __init__(self, x=None, y=None, input_fn=None,
every_n_steps=100, early_stopping_rounds=None):
super(ValidationMonitor, self).__init__(every_n_steps=every_n_steps)
if x is None and input_fn is None:
raise ValueError("Either x or input_fn should be provided.")
self.x = x
self.y = y
self.input_fn = input_fn
self.min_loss_step = 0
self.min_loss = None
self.early_stopping_rounds = early_stopping_rounds
def every_n_step_end(self, step, unused_outputs):
outputs = self._estimator.evaluate(
x=self.x, y=self.y, input_fn=self.input_fn)
stats = []
for name in outputs:
stats.append("%s = %s" % (name, str(outputs[name])))
logging.info("Validation (step %d): %s" % (step, ", ".join(stats)))
if self.early_stopping_rounds is not None:
if self.min_loss is None or outputs["loss"] < self.min_loss:
self.min_loss = outputs["loss"]
self.min_loss_step = step
stop_now = (step - self.min_loss_step >= self.early_stopping_rounds)
if stop_now:
logging.info("Stopping. Best step: {} with loss {}."
.format(self.min_loss_step, self.min_loss))
return True
return False
def get_default_monitors(loss_op=None, summary_op=None, save_summary_steps=100,
output_dir=None):
monitors = []
if loss_op is not None:
monitors.append(PrintTensor([loss_op.name]))
if summary_op is not None:
monitors.append(SummarySaver(summary_op, save_steps=save_summary_steps,
output_dir=output_dir))
return monitors

View File

@ -17,9 +17,12 @@ from __future__ import division
from __future__ import print_function
from tensorflow.contrib import layers
from tensorflow.contrib.learn.python.learn.ops import dropout_ops
from tensorflow.python.framework import ops
from tensorflow.python.ops import array_ops as array_ops_
from tensorflow.python.ops import control_flow_ops
from tensorflow.python.ops import nn
from tensorflow.python.ops import variable_scope as vs
from tensorflow.contrib.learn.python.learn.ops import dropout_ops
def dnn(tensor_in, hidden_units, activation=nn.relu, dropout=None):
@ -49,5 +52,9 @@ def dnn(tensor_in, hidden_units, activation=nn.relu, dropout=None):
if activation is not None:
tensor_in = activation(tensor_in)
if dropout is not None:
tensor_in = dropout_ops.dropout(tensor_in, prob=(1.0 - dropout))
is_training = array_ops_.squeeze(ops.get_collection('IS_TRAINING'))
tensor_in = control_flow_ops.cond(
is_training,
lambda: dropout_ops.dropout(tensor_in, prob=(1.0 - dropout)),
lambda: tensor_in)
return tensor_in

View File

@ -0,0 +1,120 @@
# Copyright 2016 Google Inc. 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 `FeedingQueueRunner` using arrays and `DataFrames`."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import numpy as np
import tensorflow as tf
import tensorflow.contrib.learn.python.learn.dataframe.queues.feeding_functions as ff
# pylint: disable=g-import-not-at-top
try:
import pandas as pd
HAS_PANDAS = True
except ImportError:
HAS_PANDAS = False
def get_rows(array, row_indices):
rows = [array[i] for i in row_indices]
return np.vstack(rows)
class FeedingQueueRunnerTestCase(tf.test.TestCase):
"""Tests for `FeedingQueueRunner`."""
def testArrayFeeding(self):
with tf.Graph().as_default():
array = np.arange(32).reshape([16, 2])
q = ff.enqueue_data(array, capacity=100)
batch_size = 3
dq_op = q.dequeue_many(batch_size)
with tf.Session() as sess:
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
for i in range(100):
indices = [j % array.shape[0]
for j in range(batch_size * i, batch_size * (i + 1))]
expected_dq = get_rows(array, indices)
dq = sess.run(dq_op)
np.testing.assert_array_equal(indices, dq[0])
np.testing.assert_array_equal(expected_dq, dq[1])
coord.request_stop()
coord.join(threads)
def testPandasFeeding(self):
if not HAS_PANDAS:
return
with tf.Graph().as_default():
array1 = np.arange(32)
array2 = np.arange(32, 64)
df = pd.DataFrame({"a": array1, "b": array2}, index=np.arange(64, 96))
q = ff.enqueue_data(df, capacity=100)
batch_size = 5
dq_op = q.dequeue_many(5)
with tf.Session() as sess:
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
for i in range(100):
indices = [j % array1.shape[0]
for j in range(batch_size * i, batch_size * (i + 1))]
expected_df_indices = df.index[indices]
expected_rows = df.iloc[indices]
dq = sess.run(dq_op)
np.testing.assert_array_equal(expected_df_indices, dq[0])
for col_num, col in enumerate(df.columns):
np.testing.assert_array_equal(expected_rows[col].values,
dq[col_num + 1])
coord.request_stop()
coord.join(threads)
def testShuffle(self):
array_size = 7
batch_size = 3
iterations = 1000
mean = batch_size * iterations * 1.0 / array_size
tolerance = 3
with tf.Graph().as_default():
array = np.arange(array_size)
q = ff.enqueue_data(array, capacity=100, shuffle=True, seed=1234)
dq_op = q.dequeue_many(batch_size)
with tf.Session() as sess:
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
counts = {x: 0 for x in array}
for _ in range(iterations):
dq = sess.run(dq_op)
for dqed in dq[1]:
self.assertIn(dqed, array)
counts[dqed] += 1
for k, v in counts.items():
self.assertGreater(
mean + tolerance, v,
"Value {} occurred {} times, expected {:.2f} +/- {}".format(
k, v, mean, tolerance))
self.assertLess(
mean - tolerance, v,
"Value {} occurred {} times, expected {:.2f} +/- {}".format(
k, v, mean, tolerance))
coord.request_stop()
coord.join(threads)
if __name__ == "__main__":
tf.test.main()

View File

@ -14,7 +14,6 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import random
@ -61,13 +60,14 @@ class BaseTest(tf.test.TestCase):
classifier.fit(iris.data, [float(x) for x in iris.target])
self.assertEqual(
classifier.get_variable_names(),
["global_step:0", "logistic_regression/weights:0",
"logistic_regression/bias:0",
["OptimizeLoss/learning_rate",
"OptimizeLoss/logistic_regression/bias/Adagrad",
"OptimizeLoss/logistic_regression/softmax_classifier/"
"softmax_cross_entropy_loss/value/avg:0",
"OptimizeLoss/learning_rate:0",
"OptimizeLoss/logistic_regression/weights/Adagrad:0",
"OptimizeLoss/logistic_regression/bias/Adagrad:0"])
"softmax_cross_entropy_loss/value/avg",
"OptimizeLoss/logistic_regression/weights/Adagrad",
"global_step",
"logistic_regression/bias",
"logistic_regression/weights"])
def testIrisSummaries(self):
iris = datasets.load_iris()
@ -84,9 +84,11 @@ class BaseTest(tf.test.TestCase):
steps=250)
classifier.fit(iris.data, iris.target)
score1 = accuracy_score(iris.target, classifier.predict(iris.data))
classifier.fit(iris.data, iris.target)
classifier.fit(iris.data, iris.target, steps=500)
score2 = accuracy_score(iris.target, classifier.predict(iris.data))
self.assertGreater(score2, score1, "Failed with score = {0}".format(score2))
self.assertGreater(
score2, score1,
"Failed with score2 {0} <= score1 {1}".format(score2, score1))
def testIrisStreaming(self):
iris = datasets.load_iris()

View File

@ -38,7 +38,8 @@ class EarlyStoppingTest(tf.test.TestCase):
X_train, X_val, y_train, y_val = train_test_split(
X_train, y_train, test_size=0.2)
val_monitor = learn.monitors.ValidationMonitor(X_val, y_val, n_classes=3)
val_monitor = learn.monitors.ValidationMonitor(X_val, y_val,
early_stopping_rounds=100)
# classifier without early stopping - overfitting
classifier1 = learn.TensorFlowDNNClassifier(hidden_units=[10, 20, 10],
@ -52,7 +53,7 @@ class EarlyStoppingTest(tf.test.TestCase):
n_classes=3,
steps=1000)
classifier2.fit(X_train, y_train, val_monitor)
classifier2.fit(X_train, y_train, monitors=[val_monitor])
score2 = accuracy_score(y_test, classifier2.predict(X_test))
# self.assertGreater(score2, score1, "No improvement using early stopping.")

View File

@ -17,6 +17,7 @@ from __future__ import print_function
import random
import numpy as np
import tensorflow as tf
from tensorflow.contrib.learn.python import learn
from tensorflow.contrib.learn.python.learn import datasets
@ -48,7 +49,7 @@ class NonLinearTest(tf.test.TestCase):
regressor = learn.TensorFlowDNNRegressor(hidden_units=[10, 20, 10],
n_classes=0,
batch_size=boston.data.shape[0],
steps=200,
steps=300,
learning_rate=0.001)
regressor.fit(boston.data, boston.target)
score = mean_squared_error(boston.target, regressor.predict(boston.data))
@ -79,6 +80,7 @@ class NonLinearTest(tf.test.TestCase):
dropout=0.1)
classifier.fit(iris.data, iris.target)
score = accuracy_score(iris.target, classifier.predict(iris.data))
# If the quality is lower - dropout is not working.
self.assertGreater(score, 0.9, "Failed with score = {0}".format(score))
def testDNNDropout0_9(self):
@ -94,7 +96,6 @@ class NonLinearTest(tf.test.TestCase):
def testRNN(self):
random.seed(42)
import numpy as np
data = np.array(
list([[2, 1, 2, 2, 3], [2, 2, 3, 4, 5], [3, 3, 1, 2, 1], [2, 4, 5, 4, 1]
]),
@ -103,7 +104,8 @@ class NonLinearTest(tf.test.TestCase):
labels = np.array(list([1, 0, 1, 0]), dtype=np.float32)
# targets for regression
targets = np.array(list([10, 16, 10, 16]), dtype=np.float32)
test_data = np.array(list([[1, 3, 3, 2, 1], [2, 3, 4, 5, 6]]))
test_data = np.array(list([[1, 3, 3, 2, 1], [2, 3, 4, 5, 6]]),
dtype=np.float32)
def input_fn(X):
return tf.split(1, 5, X)
@ -144,7 +146,6 @@ class NonLinearTest(tf.test.TestCase):
def testBidirectionalRNN(self):
random.seed(42)
import numpy as np
data = np.array(
list([[2, 1, 2, 2, 3], [2, 2, 3, 4, 5], [3, 3, 1, 2, 1], [2, 4, 5, 4, 1]
]),
@ -161,19 +162,20 @@ class NonLinearTest(tf.test.TestCase):
input_op_fn=input_fn,
bidirectional=True)
classifier.fit(data, labels)
predictions = classifier.predict(np.array(list([[1, 3, 3, 2, 1], [2, 3, 4,
5, 6]])))
test_data = np.array(list([[1, 3, 3, 2, 1], [2, 3, 4,
5, 6]]), dtype=np.float32)
predictions = classifier.predict(test_data)
self.assertAllClose(predictions, np.array([1, 0]))
def testDNNAutoencoder(self):
import numpy as np
iris = datasets.load_iris()
autoencoder = learn.TensorFlowDNNAutoencoder(hidden_units=[10, 20])
transformed = autoencoder.fit_transform(iris.data[1:2])
expected = np.array([[ -3.57627869e-07, 1.17000043e+00, 1.01902664e+00, 1.19209290e-07,
0.00000000e+00, 1.19209290e-07, -5.96046448e-08, -2.38418579e-07,
9.74681854e-01, 1.19209290e-07]])
self.assertAllClose(transformed, expected)
# def testDNNAutoencoder(self):
# import numpy as np
# iris = datasets.load_iris()
# autoencoder = learn.TensorFlowDNNAutoencoder(hidden_units=[10, 20])
# transformed = autoencoder.fit_transform(iris.data[1:2])
# expected = np.array([[ -3.57627869e-07, 1.17000043e+00, 1.01902664e+00, 1.19209290e-07,
# 0.00000000e+00, 1.19209290e-07, -5.96046448e-08, -2.38418579e-07,
# 9.74681854e-01, 1.19209290e-07]])
# self.assertAllClose(transformed, expected)
if __name__ == "__main__":

View File

@ -33,10 +33,10 @@ class SaverTest(tf.test.TestCase):
classifier = learn.TensorFlowLinearClassifier(n_classes=3)
classifier.fit(iris.data, iris.target)
classifier.save(path)
new_classifier = learn.TensorFlowEstimator.restore(path)
self.assertEqual(type(new_classifier), type(classifier))
score = accuracy_score(iris.target, new_classifier.predict(iris.data))
self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score))
# new_classifier = learn.TensorFlowEstimator.restore(path)
# self.assertEqual(type(new_classifier), type(classifier))
# score = accuracy_score(iris.target, new_classifier.predict(iris.data))
# self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score))
def testCustomModel(self):
path = tf.test.get_temp_dir() + '/tmp.saver2'
@ -49,10 +49,10 @@ class SaverTest(tf.test.TestCase):
classifier = learn.TensorFlowEstimator(model_fn=custom_model, n_classes=3)
classifier.fit(iris.data, iris.target)
classifier.save(path)
new_classifier = learn.TensorFlowEstimator.restore(path)
self.assertEqual(type(new_classifier), type(classifier))
score = accuracy_score(iris.target, new_classifier.predict(iris.data))
self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score))
# new_classifier = learn.TensorFlowEstimator.restore(path)
# self.assertEqual(type(new_classifier), type(classifier))
# score = accuracy_score(iris.target, new_classifier.predict(iris.data))
# self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score))
def testDNN(self):
path = tf.test.get_temp_dir() + '/tmp_saver3'
@ -62,10 +62,10 @@ class SaverTest(tf.test.TestCase):
n_classes=3)
classifier.fit(iris.data, iris.target)
classifier.save(path)
new_classifier = learn.TensorFlowEstimator.restore(path)
self.assertEqual(type(new_classifier), type(classifier))
score = accuracy_score(iris.target, new_classifier.predict(iris.data))
self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score))
# new_classifier = learn.TensorFlowEstimator.restore(path)
# self.assertEqual(type(new_classifier), type(classifier))
# score = accuracy_score(iris.target, new_classifier.predict(iris.data))
# self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score))
def testNoFolder(self):
with self.assertRaises(ValueError):
@ -80,7 +80,7 @@ class SaverTest(tf.test.TestCase):
classifier.fit(iris.data, iris.target)
classifier.save(path)
os.remove(os.path.join(path, 'checkpoint'))
with self.assertRaises(ValueError):
with self.assertRaises(NotImplementedError):
learn.TensorFlowEstimator.restore(path)
if __name__ == '__main__':

View File

@ -1,4 +1,7 @@
"""Generic trainer for TensorFlow models."""
"""Generic trainer for TensorFlow models.
This module is deprecated, please use graph_actions.
"""
# Copyright 2015-present The Scikit Flow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@ -19,6 +22,8 @@ from __future__ import print_function
from six.moves import xrange # pylint: disable=redefined-builtin
from tensorflow.python.platform import tf_logging as logging
def train(session,
train_op,
@ -45,6 +50,8 @@ def train(session,
summaries: Joined object of all summaries that should be ran.
feed_params_fn: Feed params function.
"""
logging.warning("learn.trainer.train is deprecated. "
"Please use learn.graph_actions.train instead.")
for step in xrange(steps):
feed_dict = feed_dict_fn()
if summaries is not None:
@ -55,13 +62,5 @@ def train(session,
global_step_value, loss_value, _ = session.run(
[global_step, loss, train_op],
feed_dict=feed_dict)
monitor.update(step,
global_step_value,
loss_value,
session,
feed_params_fn,
loss_expression_tensor=loss)
if summaries is not None and summary_writer and summ is not None:
summary_writer.add_summary(summ, global_step_value)
if monitor.monitor_inducing_stop():
break

View File

@ -20,16 +20,23 @@ from __future__ import print_function
import six
from tensorflow.python.framework import dtypes
from tensorflow.python.ops import script_ops
from tensorflow.python.ops import gen_io_ops
from tensorflow.python.ops import state_ops
from tensorflow.python.ops import variable_scope as vs
from tensorflow.python.ops import variables
from tensorflow.python.platform import gfile
from tensorflow.python.platform import tf_logging as logging
from tensorflow.python.training import saver
from tensorflow.python.training import training as train
def _get_checkpoint_filename(filepattern):
"""Returns checkpoint filename given directory or specific filepattern."""
if gfile.IsDirectory(filepattern):
return saver.latest_checkpoint(filepattern)
return filepattern
def load_checkpoint(filepattern):
"""Returns CheckpointReader for latest checkpoint.
@ -42,13 +49,11 @@ def load_checkpoint(filepattern):
Raises:
ValueError: if checkpoint_dir doesn't have 'checkpoint' file or checkpoints.
"""
if gfile.IsDirectory(filepattern):
filename = saver.latest_checkpoint(filepattern)
if filename is None:
raise ValueError("Couldn't find 'checkpoint' file or checkpoints in "
"given directory %s" % filepattern)
return train.NewCheckpointReader(filename)
return train.NewCheckpointReader(filepattern)
filename = _get_checkpoint_filename(filepattern)
if filename is None:
raise ValueError("Couldn't find 'checkpoint' file or checkpoints in "
"given directory %s" % filepattern)
return train.NewCheckpointReader(filename)
def load_variable(checkpoint_dir, name):
@ -83,43 +88,49 @@ def list_variables(checkpoint_dir):
return result
def _checkpoint_initializer(variable, checkpoint_reader, tensor_name):
"""Assigns variable to value that will be loaded from checkpoint's tensor.
# pylint: disable=protected-access
# Currently variable_scope doesn't provide very good APIs to access
# all variables under scope and retrieve and check existing scopes.
# TODO(ipolosukhin): Refactor variable_scope module to provide nicer APIs.
def _set_checkpoint_initializer(variable, file_pattern, tensor_name, slice_spec,
name="checkpoint_initializer"):
"""Sets variable initializer to assign op form value in checkpoint's tensor.
Args:
variable: `Variable` object.
checkpoint_reader: `CheckpointReader` object.
file_pattern: string, where to load checkpoints from.
tensor_name: Name of the `Tensor` to load from checkpoint reader.
Returns:
`Tensor` that returns value of `tensor_name` in checkpoint.
Raises:
ValueError: if shape or dtype of `variable` doesn't match with Tensor in
checkpoint.
slice_spec: Slice specification for loading partitioned variables.
name: Name of the operation.
"""
# Currently to avoid putting the whole tensor into the graph, this adds a
# py_func function to the graph, that will return actual value.
# TODO(ipolosukhin): Rewrite this as C++ op, that loads checkpoint at time.
tensor = checkpoint_reader.get_tensor(tensor_name)
def _tensor():
return tensor
if not variable.get_shape().is_compatible_with(tensor.shape):
raise ValueError(
"Shape of variable %s (%s) doesn't match with shape of "
"tensor %s (%s) from checkpoint reader." % (
variable.name, str(variable.get_shape()),
tensor_name, str(tensor.shape)
))
if not dtypes.as_dtype(tensor.dtype).is_compatible_with(variable.dtype):
raise ValueError(
"DType of variable %s (%s) doesn't match with dtype of "
"tensor %s (%s) from checkpoint reader." % (
variable.name, str(variable.dtype),
tensor_name, str(dtypes.as_dtype(tensor.dtype))
))
return state_ops.assign(
variable, script_ops.py_func(_tensor, [], [tensor.dtype])[0])
base_type = variable.dtype.base_dtype
restore_op = gen_io_ops._restore_slice(
file_pattern,
tensor_name,
slice_spec,
base_type,
preferred_shard=-1,
name=name)
variable._initializer_op = state_ops.assign(variable, restore_op)
def _set_variable_or_list_initializer(variable_or_list, file_pattern,
tensor_name):
if isinstance(variable_or_list, (list, tuple)):
# A set of slices.
slice_name = None
for v in variable_or_list:
if slice_name is None:
slice_name = v._save_slice_info.full_name
elif slice_name != v._save_slice_info.full_name:
raise ValueError("Slices must all be from the same tensor: %s != %s" %
(slice_name, v._save_slice_info.full_name))
_set_checkpoint_initializer(v, file_pattern, tensor_name,
v._save_slice_info.spec)
else:
_set_checkpoint_initializer(variable_or_list, file_pattern, tensor_name, "")
def init_from_checkpoint(checkpoint_dir, assignment_map):
@ -133,8 +144,15 @@ def init_from_checkpoint(checkpoint_dir, assignment_map):
current `scope_name` from `checkpoint_scope_name` with matching variable
names.
`'scope_name/variable_name': 'checkpoint_scope_name/some_other_variable'` -
will initalize `scope_name/variable_name` variable
from `checkpoint_scope_name/some_other_variable`.
will initalize `scope_name/variable_name` variable
from `checkpoint_scope_name/some_other_variable`.
`variable: 'scope_varaible_name'` - will initialize given variable with
variable from the checkpoint.
`'scope_name/': '/'` - will load all variables in current `scope_name` from
checkpoint's root (e.g. no scope).
Supports loading into partitioned variables, which are represented as
'<variable>/part_<part #>'.
Example:
```python
@ -142,13 +160,18 @@ def init_from_checkpoint(checkpoint_dir, assignment_map):
with tf.variable_scope('test'):
m = tf.get_variable('my_var')
with tf.variable_scope('test2'):
m = tf.get_variable('my_var')
var2 = tf.get_variable('my_var')
...
# Specify which variables to intialize from checkpoint.
init_from_checkpoint(checkpoint_dir, {
'test/my_var': 'some_var',
'test2/', 'some_scope/'})
...
# Or use `Variable` objects to identify what to initialize.
init_from_checkpoint(checkpoint_dir, {
var2: 'some_scope/var2',
})
...
# Initialize variables as usual.
session.run(tf.get_all_variables())
```
@ -163,26 +186,50 @@ def init_from_checkpoint(checkpoint_dir, assignment_map):
tf.errors.OpError: If missing checkpoints or tensors in checkpoints.
ValueError: If missing variables in current graph.
"""
filepattern = _get_checkpoint_filename(checkpoint_dir)
reader = load_checkpoint(checkpoint_dir)
variable_map = reader.get_variable_to_shape_map()
for current_name, tensor_name in six.iteritems(assignment_map):
scopes = ""
if "/" in current_name:
scopes = current_name[:current_name.rindex("/")]
current_name = current_name[current_name.rindex("/") + 1:]
if current_name:
var = None
# Check if this is Variable object.
if isinstance(current_name, variables.Variable):
var = current_name
else:
var_scope = vs._get_default_variable_store()
# Check if this is variable in var_store.
var = var_scope._vars.get(current_name, None)
# Also check if variable is partitioned as list.
if var is None:
if current_name + "/part_0" in var_scope._vars:
var = []
i = 0
while current_name + "/part_%d" % i in var_scope._vars:
var.append(var_scope._vars[current_name + "/part_%d" % i])
i += 1
if var is not None:
# If 1 to 1 mapping was provided, find variable in the scope.
if tensor_name not in variable_map:
raise ValueError("Tensor %s is not found in %s checkpoint" % (
tensor_name, checkpoint_dir
))
with vs.variable_scope(scopes, reuse=True):
var = vs.get_variable(current_name)
var._initializer_op = _checkpoint_initializer(var, reader, tensor_name) # pylint: disable=protected-access
logging.info("Initialize variable %s from checkpoint %s with %s" % (
var.name, checkpoint_dir, tensor_name
))
if isinstance(var, variables.Variable):
# Additional at-call-time checks.
if not var.get_shape().is_compatible_with(variable_map[tensor_name]):
raise ValueError(
"Shape of variable %s (%s) doesn't match with shape of "
"tensor %s (%s) from checkpoint reader." % (
var.name, str(var.get_shape()),
tensor_name, str(variable_map[tensor_name])
))
_set_variable_or_list_initializer(var, filepattern, tensor_name)
logging.info("Initialize variable %s from checkpoint %s with %s" % (
current_name, checkpoint_dir, tensor_name
))
else:
if "/" in current_name:
scopes = current_name[:current_name.rindex("/")]
current_name = current_name[current_name.rindex("/") + 1:]
if not tensor_name.endswith("/"):
raise ValueError(
"Assignment map with scope only name (%s) "
@ -191,21 +238,23 @@ def init_from_checkpoint(checkpoint_dir, assignment_map):
scopes, tensor_name
))
# If scope to scope mapping was provided, find all variables in the scope.
# TODO(ipolosukhin): Refactor variable_scope module to provide nicer APIs.
var_scope = vs._get_default_variable_store() # pylint: disable=protected-access
for var_name in var_scope._vars: # pylint: disable=protected-access
for var_name in var_scope._vars:
if var_name.startswith(scopes):
# Lookup name with specified prefix and suffix from current variable.
full_tensor_name = tensor_name + var_name[len(scopes) + 1:]
# If tensor_name given is '/' (root), don't use it for full name.
if tensor_name != "/":
full_tensor_name = tensor_name + var_name[len(scopes) + 1:]
else:
full_tensor_name = var_name[len(scopes) + 1:]
if full_tensor_name not in variable_map:
raise ValueError(
"Tensor %s (%s in %s) is not found in %s checkpoint" % (
full_tensor_name, var_name[len(scopes) + 1:], tensor_name,
checkpoint_dir
))
var = var_scope._vars[var_name] # pylint: disable=protected-access
var._initializer_op = _checkpoint_initializer( # pylint: disable=protected-access
var, reader, full_tensor_name)
var = var_scope._vars[var_name]
_set_variable_or_list_initializer(var, filepattern, full_tensor_name)
logging.info("Initialize variable %s from checkpoint %s with %s" % (
var_name, checkpoint_dir, tensor_name
))
# pylint: enable=protected-access

View File

@ -41,6 +41,24 @@ def _create_checkpoints(sess, checkpoint_dir):
return v1_value, v2_value, v3_value, v4_value
def _create_partition_checkpoints(sess, checkpoint_dir):
checkpoint_prefix = os.path.join(checkpoint_dir, "model")
checkpoint_state_name = "checkpoint"
# TODO(ipolosukhin): Enable this when get_variable partitioning works.
# v1 = tf.get_variable("var1", [100, 100],
# partitioner=tf.variable_axis_size_partitioner(axis=0,
# max_shard_bytes=512))
v1 = tf.create_partitioned_variables(
shape=[100, 100], slicing=[5, 1], name="var1",
initializer=tf.truncated_normal_initializer(0.5))
sess.run(tf.initialize_all_variables())
v1_value = sess.run(v1)
saver = tf.train.Saver()
saver.save(sess, checkpoint_prefix, global_step=0,
latest_filename=checkpoint_state_name)
return v1_value
class CheckpointsTest(tf.test.TestCase):
def testNoCheckpoints(self):
@ -97,7 +115,7 @@ class CheckpointsTest(tf.test.TestCase):
})
checkpoints.init_from_checkpoint(checkpoint_dir, {
"some_scope/some_other_scope/my2": "var2",
"my3": "var3",
my3: "var3",
})
session.run(tf.initialize_all_variables())
@ -107,7 +125,60 @@ class CheckpointsTest(tf.test.TestCase):
self.assertAllEqual(my4.eval(session), v4)
# Check that tensors are not explicitly in the graph.
self.assertLess(len(str(session.graph.as_graph_def())), 22000)
self.assertLess(len(str(session.graph.as_graph_def())), 26000)
def testInitFromRootCheckpoint(self):
checkpoint_dir = self.get_temp_dir()
with self.test_session() as session:
v1, v2, v3, v4 = _create_checkpoints(session, checkpoint_dir)
# New graph and session.
with tf.Graph().as_default() as g:
with self.test_session(graph=g) as session:
with tf.variable_scope("some_scope"):
my1 = tf.get_variable("var1", [1, 10])
my2 = tf.get_variable("var2", [10, 10])
my3 = tf.get_variable("var3", [100, 100])
with tf.variable_scope("useful_scope"):
my4 = tf.get_variable("var4", [9, 9])
checkpoints.init_from_checkpoint(checkpoint_dir, {
"some_scope/": "/",
})
session.run(tf.initialize_all_variables())
self.assertAllEqual(my1.eval(session), v1)
self.assertAllEqual(my2.eval(session), v2)
self.assertAllEqual(my3.eval(session), v3)
self.assertAllEqual(my4.eval(session), v4)
def testInitFromPartitionVar(self):
checkpoint_dir = self.get_temp_dir()
with self.test_session() as session:
v1 = _create_partition_checkpoints(session, checkpoint_dir)
# New graph and session.
with tf.Graph().as_default() as g:
with self.test_session(graph=g) as session:
with tf.variable_scope("some_scope"):
# TODO(ipolosukhin): Enable this when get_variable partitioning works.
# Currently get_variable with partitioner doesn't return Variable,
# but returns a concat op.
# my1 = tf.get_variable(
# "my1", [100, 100],
# partitioner=tf.variable_axis_size_partitioner(axis=0,
# max_shard_bytes=100))
my1 = tf.create_partitioned_variables(
shape=[100, 100], slicing=[5, 1], name="my1",
initializer=tf.truncated_normal_initializer(0.5))
checkpoints.init_from_checkpoint(checkpoint_dir, {
"some_scope/my1": "var1",
})
session.run(tf.initialize_all_variables())
my1_values = session.run(my1)
self.assertAllEqual(my1_values, v1)
def testInitFromCheckpointMissing(self):
checkpoint_dir = self.get_temp_dir()
@ -142,11 +213,6 @@ class CheckpointsTest(tf.test.TestCase):
checkpoints.init_from_checkpoint(checkpoint_dir, {
"some_scope/my1": "var1"})
# DType mismatch.
with self.assertRaises(ValueError):
checkpoints.init_from_checkpoint(checkpoint_dir, {
"some_scope/my2": "var1"})
# Variable 'my1' and 'my2' are missing in given checkpoint scope.
with self.assertRaises(ValueError):
checkpoints.init_from_checkpoint(checkpoint_dir, {

View File

@ -146,8 +146,10 @@ from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_mean_rela
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_mean_squared_error
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_percentage_less
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_precision
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_precision_at_thresholds
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_recall
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_recall_at_k
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_recall_at_thresholds
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_root_mean_squared_error
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_sparse_precision_at_k
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_sparse_recall_at_k

View File

@ -28,7 +28,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 check_ops
from tensorflow.python.ops import logging_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import nn
from tensorflow.python.ops import sparse_ops
@ -406,9 +405,9 @@ def streaming_precision(predictions, labels, ignore_mask=None,
Raises:
ValueError: If the dimensions of `predictions` and `labels` don't match or
if `weight` is not `None` and its shape doesn't match `predictions` or
if either `metrics_collections` or `updates_collections` are not
a list or tuple.
if `ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
"""
with variable_scope.variable_op_scope(
[predictions, labels], name, 'precision'):
@ -485,9 +484,9 @@ def streaming_recall(predictions, labels, ignore_mask=None,
Raises:
ValueError: If the dimensions of `predictions` and `labels` don't match or
if `weight` is not `None` and its shape doesn't match `predictions` or
if either `metrics_collections` or `updates_collections` are not
a list or tuple.
if `ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
"""
with variable_scope.variable_op_scope([predictions, labels], name, 'recall'):
predictions, labels = _remove_squeezable_dimensions(predictions, labels)
@ -521,6 +520,139 @@ def streaming_recall(predictions, labels, ignore_mask=None,
return recall, update_op
def _tp_fn_tn_fp(predictions, labels, thresholds, ignore_mask=None):
"""Computes true_positives, false_negatives, true_negatives, false_positives.
The `_tp_fn_tn_fp` function creates four local variables, `true_positives`,
`true_negatives`, `false_positives` and `false_negatives`.
`true_positive[i]` is defined` as the number of values in `predictions` above
`thresholds[i]` whose corresponding entry in `labels` is `True`.
`false_negatives[i]` is defined` as the number of values in `predictions` at
most `thresholds[i]` whose corresponding entry in `labels` is `True`.
`true_negatives[i]` is defined` as the number of values in `predictions` at
most `thresholds[i]` whose corresponding entry in `labels` is `False`.
`false_positives[i]` is defined` as the number of values in `predictions`
above `thresholds[i]` whose corresponding entry in `labels` is `False`.
These four variables are updated through the `update_op`.
The streaming behavior is that the values of the variables after a few
`update_op`s is the same as if the inputs had been concatenated and a single
`update_op` had been performed.
If `ignore_mask` is not `None`, then the increment of the variables is
performed using only the elements of `predictions` and `labels` whose
corresponding value in `ignore_mask` is `False`.
Args:
predictions: A floating point `Tensor` of arbitrary shape and whose values
are in the range `[0, 1]`.
labels: A binary `Tensor` whose shape matches `predictions`.
thresholds: A python list or tuple of float thresholds in `[0, 1]`.
ignore_mask: An optional, binary tensor whose size matches `predictions`.
Returns:
true_positive: A variable of shape [len(thresholds)].
false_negative: A variable of shape [len(thresholds)].
true_negatives: A variable of shape [len(thresholds)].
false_positives: A variable of shape [len(thresholds)].
true_positives_update_op: An operation that increments the `true_positives`.
false_negative_update_op: An operation that increments the `false_negative`.
true_negatives_update_op: An operation that increments the `true_negatives`.
false_positives_update_op: An operation that increments the
`false_positives`.
Raises:
ValueError: If the shape of `predictions` and `labels` do not match or if
`ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
"""
predictions, labels = _remove_squeezable_dimensions(predictions, labels)
predictions.get_shape().assert_is_compatible_with(labels.get_shape())
num_thresholds = len(thresholds)
# Reshape predictions and labels to be column vectors
predictions = array_ops.reshape(predictions, [-1, 1])
labels = array_ops.reshape(labels, [-1, 1])
# Use static shape if known.
num_predictions = predictions.get_shape().as_list()[0]
# Otherwise use dynamic shape.
if num_predictions is None:
num_predictions = array_ops.shape(predictions)[0]
thresh_tiled = array_ops.tile(
array_ops.expand_dims(array_ops.constant(thresholds), [1]),
array_ops.pack([1, num_predictions]))
# Tile the predictions after thresholding them across different thresholds.
pred_tiled = math_ops.cast(
math_ops.greater(
array_ops.tile(
array_ops.transpose(predictions), [num_thresholds, 1]),
thresh_tiled),
dtype=dtypes.int32)
# Tile labels by number of thresholds
labels_tiled = array_ops.tile(array_ops.transpose(labels),
[num_thresholds, 1])
true_positives = _create_local('true_positives', shape=[num_thresholds])
false_negatives = _create_local('false_negatives', shape=[num_thresholds])
true_negatives = _create_local('true_negatives', shape=[num_thresholds])
false_positives = _create_local('false_positives', shape=[num_thresholds])
is_true_positive = math_ops.to_float(
math_ops.logical_and(
math_ops.equal(labels_tiled, 1), math_ops.equal(pred_tiled, 1)))
is_false_negative = math_ops.to_float(
math_ops.logical_and(
math_ops.equal(labels_tiled, 1), math_ops.equal(pred_tiled, 0)))
is_false_positive = math_ops.to_float(
math_ops.logical_and(
math_ops.equal(labels_tiled, 0), math_ops.equal(pred_tiled, 1)))
is_true_negative = math_ops.to_float(
math_ops.logical_and(
math_ops.equal(labels_tiled, 0), math_ops.equal(pred_tiled, 0)))
if ignore_mask is not None:
ignore_mask = array_ops.reshape(ignore_mask, [-1, 1])
mask_tiled = array_ops.tile(array_ops.transpose(ignore_mask),
[num_thresholds, 1])
labels_tiled.get_shape().assert_is_compatible_with(mask_tiled.get_shape())
check_ops.assert_type(mask_tiled, dtypes.bool)
is_true_positive = math_ops.select(
mask_tiled,
array_ops.zeros_like(labels_tiled, dtype=dtypes.float32),
is_true_positive)
is_false_negative = math_ops.select(
mask_tiled,
array_ops.zeros_like(labels_tiled, dtype=dtypes.float32),
is_false_negative)
is_false_positive = math_ops.select(
mask_tiled,
array_ops.zeros_like(labels_tiled, dtype=dtypes.float32),
is_false_positive)
is_true_negative = math_ops.select(
mask_tiled,
array_ops.zeros_like(labels_tiled, dtype=dtypes.float32),
is_true_negative)
true_positives_update_op = state_ops.assign_add(
true_positives, math_ops.reduce_sum(is_true_positive, 1))
false_negatives_update_op = state_ops.assign_add(
false_negatives, math_ops.reduce_sum(is_false_negative, 1))
true_negatives_update_op = state_ops.assign_add(
true_negatives, math_ops.reduce_sum(is_true_negative, 1))
false_positives_update_op = state_ops.assign_add(
false_positives, math_ops.reduce_sum(is_false_positive, 1))
return (true_positives, false_negatives, true_negatives, false_positives,
true_positives_update_op, false_negatives_update_op,
true_negatives_update_op, false_positives_update_op)
def streaming_auc(predictions, labels, ignore_mask=None, num_thresholds=200,
metrics_collections=None, updates_collections=None,
name=None):
@ -541,12 +673,12 @@ def streaming_auc(predictions, labels, ignore_mask=None, num_thresholds=200,
To faciliate the estimation of the AUC over a stream of data, the function
creates an `update_op` operation whose behavior is dependent on the value of
`weights`. If `weights` is None, then `update_op` increments the
`ignore_mask`. If `ignore_mask` is None, then `update_op` increments the
`true_positives`, `true_negatives`, `false_positives` and `false_negatives`
counts with the number of each found in the current `predictions` and `labels`
`Tensors`. If `weights` is not `None`, then the increment is performed using
only the elements of `predictions` and `labels` whose corresponding value
in `ignore_mask` is `False`. In addition to performing the updates,
`Tensors`. If `ignore_mask` is not `None`, then the increment is performed
using only the elements of `predictions` and `labels` whose corresponding
value in `ignore_mask` is `False`. In addition to performing the updates,
`update_op` also returns the `auc`.
Args:
@ -563,108 +695,27 @@ def streaming_auc(predictions, labels, ignore_mask=None, num_thresholds=200,
name: An optional variable_op_scope name.
Returns:
auc: A tensor representing the current area-under-curve.
auc: A scalar tensor representing the current area-under-curve.
update_op: An operation that increments the `true_positives`,
`true_negatives`, `false_positives` and `false_negatives` variables
appropriately and whose value matches `auc`.
Raises:
ValueError: If the shape of `predictions` and `labels` do not match or if
`weights` is not `None` and its shape doesn't match `values`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
`ignore_mask` is not `None` and its shape doesn't match `predictions` or
if either `metrics_collections` or `updates_collections` are not a list or
tuple.
"""
with variable_scope.variable_op_scope([predictions, labels], name, 'auc'):
predictions, labels = _remove_squeezable_dimensions(predictions, labels)
predictions.get_shape().assert_is_compatible_with(labels.get_shape())
kepsilon = 1e-7 # to account for floating point imprecisions
thresholds = [(i + 1) * 1.0 / (num_thresholds - 1)
for i in range(num_thresholds-2)]
thresholds = [0.0 - kepsilon] + thresholds + [1.0 + kepsilon]
# Reshape predictions and labels to be column vectors
logging_ops.Assert(
math_ops.equal(
array_ops.rank(predictions), 1),
['Input predictions are expected to be a rank 1 tensor. Got ',
array_ops.rank(predictions)])
logging_ops.Assert(
math_ops.equal(
array_ops.rank(labels), 1),
['Input labels are expected to be a rank 1 tensor. Got ',
array_ops.rank(labels)])
predictions = array_ops.reshape(predictions, [-1, 1])
labels = array_ops.reshape(labels, [-1, 1])
kepsilon = 1e-7
# Use static shape if known.
num_predictions = predictions.get_shape().as_list()[0]
# Otherwise use dynamic shape.
if num_predictions is None:
num_predictions = array_ops.shape(predictions)[0]
thresh_tiled = array_ops.tile(
array_ops.expand_dims(
math_ops.linspace(0.0 - kepsilon, 1.0 + kepsilon, num_thresholds),
[1]),
array_ops.pack([1, num_predictions]))
# Tile the predictions after thresholding them across different thresholds.
pred_tiled = math_ops.cast(
math_ops.greater(
array_ops.tile(
array_ops.transpose(predictions), [num_thresholds, 1]),
thresh_tiled),
dtype=dtypes.int32)
# Tile labels by number of thresholds
labels_tiled = array_ops.tile(array_ops.transpose(labels),
[num_thresholds, 1])
true_positives = _create_local('true_positives', shape=[num_thresholds])
false_negatives = _create_local('false_negatives', shape=[num_thresholds])
true_negatives = _create_local('true_negatives', shape=[num_thresholds])
false_positives = _create_local('false_positives', shape=[num_thresholds])
is_true_positive = math_ops.to_float(
math_ops.logical_and(
math_ops.equal(labels_tiled, 1), math_ops.equal(pred_tiled, 1)))
is_false_negative = math_ops.to_float(
math_ops.logical_and(
math_ops.equal(labels_tiled, 1), math_ops.equal(pred_tiled, 0)))
is_false_positive = math_ops.to_float(
math_ops.logical_and(
math_ops.equal(labels_tiled, 0), math_ops.equal(pred_tiled, 1)))
is_true_negative = math_ops.to_float(
math_ops.logical_and(
math_ops.equal(labels_tiled, 0), math_ops.equal(pred_tiled, 0)))
if ignore_mask is not None:
mask_tiled = array_ops.tile(array_ops.transpose(ignore_mask),
[num_thresholds, 1])
labels_tiled.get_shape().assert_is_compatible_with(mask_tiled.get_shape())
check_ops.assert_type(mask_tiled, dtypes.bool)
is_true_positive = math_ops.select(
mask_tiled,
array_ops.zeros_like(labels_tiled, dtype=dtypes.float32),
is_true_positive)
is_false_negative = math_ops.select(
mask_tiled,
array_ops.zeros_like(labels_tiled, dtype=dtypes.float32),
is_false_negative)
is_false_positive = math_ops.select(
mask_tiled,
array_ops.zeros_like(labels_tiled, dtype=dtypes.float32),
is_false_positive)
is_true_negative = math_ops.select(
mask_tiled,
array_ops.zeros_like(labels_tiled, dtype=dtypes.float32),
is_true_negative)
true_positives_compute_op = state_ops.assign_add(
true_positives, math_ops.reduce_sum(is_true_positive, 1))
false_negatives_compute_op = state_ops.assign_add(
false_negatives, math_ops.reduce_sum(is_false_negative, 1))
true_negatives_compute_op = state_ops.assign_add(
true_negatives, math_ops.reduce_sum(is_true_negative, 1))
false_positives_compute_op = state_ops.assign_add(
false_positives, math_ops.reduce_sum(is_false_positive, 1))
(true_positives, false_negatives, true_negatives, false_positives,
true_positives_compute_op, false_negatives_compute_op,
true_negatives_compute_op, false_positives_compute_op) = _tp_fn_tn_fp(
predictions, labels, thresholds, ignore_mask)
epsilon = 1.0e-6
assert array_ops.squeeze(
@ -698,6 +749,149 @@ def streaming_auc(predictions, labels, ignore_mask=None, num_thresholds=200,
return auc, update_op
def streaming_precision_at_thresholds(predictions, labels, thresholds,
ignore_mask=None,
metrics_collections=None,
updates_collections=None, name=None):
"""Computes precision values for different `thresholds` on `predictions`.
The `streaming_precision_at_thresholds` function creates four local variables,
`true_positives`, `true_negatives`, `false_positives` and `false_negatives`
for various values of thresholds.
`precision[i]` is defined as the number of values in `predictions` above
`thresholds[i]` whose corresponding entry in `labels` is `True`
(`true_positives[i]`) divided by the number of values in `predictions`
above `thresholds[i]` (`true_positives[i] + false_positives[i]`).
If `ignore_mask` is not None then only values whose corresponding value in
`ignore_mask` is `False` are considered.
`precision` is returned along with an `update_op` whose value equals that of
`precision`.
Args:
predictions: A floating point `Tensor` of arbitrary shape and whose values
are in the range `[0, 1]`.
labels: A binary `Tensor` whose shape matches `predictions`.
thresholds: A python list or tuple of float thresholds in `[0, 1]`.
ignore_mask: An optional, binary tensor whose size matches `predictions`.
metrics_collections: An optional list of collections that `auc` should be
added to.
updates_collections: An optional list of collections that `update_op` should
be added to.
name: An optional variable_op_scope name.
Returns:
precision: A float tensor of shape [len(thresholds)].
update_op: An operation that increments the `true_positives`,
`true_negatives`, `false_positives` and `false_negatives` variables that
are used in the computation of `precision`.
Raises:
ValueError: If the shape of `predictions` and `labels` do not match or if
`ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
"""
with variable_scope.variable_op_scope([predictions, labels], name,
'precision_at_thresholds'):
(true_positives, _, _, false_positives, true_positives_compute_op, _, _,
false_positives_compute_op,) = _tp_fn_tn_fp(
predictions, labels, thresholds, ignore_mask)
# avoid division by zero
epsilon = 1e-7
def compute_precision(name):
precision = math_ops.div(true_positives,
epsilon + true_positives + false_positives,
name='precision_' + name)
return precision
precision = compute_precision('value')
with ops.control_dependencies([true_positives_compute_op,
false_positives_compute_op]):
update_op = compute_precision('update_op')
if metrics_collections:
ops.add_to_collections(metrics_collections, precision)
if updates_collections:
ops.add_to_collections(updates_collections, update_op)
return precision, update_op
def streaming_recall_at_thresholds(predictions, labels, thresholds,
ignore_mask=None, metrics_collections=None,
updates_collections=None, name=None):
"""Computes various recall values for different `thresholds` on `predictions`.
The `streaming_recall_at_thresholds` function creates four local variables,
`true_positives`, `true_negatives`, `false_positives` and `false_negatives`
for various values of thresholds.
`recall[i]` is defined as the number of values in `predictions` above
`thresholds[i]` whose corresponding entry in `labels` is `True`
(`true_positives[i]`) divided by the number of True values in `labels`
(`true_positives[i] + false_negatives[i]`).
If `ignore_mask` is not None then only values whose corresponding value in
`ignore_mask` is `False` are considered.
`recall` are returned along with an `update_op` whose value equals that of
`recall`.
Args:
predictions: A floating point `Tensor` of arbitrary shape and whose values
are in the range `[0, 1]`.
labels: A binary `Tensor` whose shape matches `predictions`.
thresholds: A python list or tuple of float thresholds in `[0, 1]`.
ignore_mask: An optional, binary tensor whose size matches `predictions`.
metrics_collections: An optional list of collections that `auc` should be
added to.
updates_collections: An optional list of collections that `update_op` should
be added to.
name: An optional variable_op_scope name.
Returns:
recall: A float tensor of shape [len(thresholds)].
update_op: An operation that increments the `true_positives`,
`true_negatives`, `false_positives` and `false_negatives` variables that
are used in the computation of `recall`.
Raises:
ValueError: If the shape of `predictions` and `labels` do not match or if
`ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
"""
with variable_scope.variable_op_scope([predictions, labels], name,
'recall_at_thresholds'):
(true_positives, false_negatives, _, _, true_positives_compute_op,
false_negatives_compute_op, _, _,) = _tp_fn_tn_fp(
predictions, labels, thresholds, ignore_mask)
# avoid division by zero
epsilon = 1e-7
def compute_recall(name):
recall = math_ops.div(true_positives,
epsilon + true_positives + false_negatives,
name='recall_' + name)
return recall
recall = compute_recall('value')
with ops.control_dependencies([true_positives_compute_op,
false_negatives_compute_op]):
update_op = compute_recall('update_op')
if metrics_collections:
ops.add_to_collections(metrics_collections, recall)
if updates_collections:
ops.add_to_collections(updates_collections, update_op)
return recall, update_op
def streaming_recall_at_k(predictions, labels, k, ignore_mask=None,
metrics_collections=None, updates_collections=None,
name=None):
@ -741,9 +935,9 @@ def streaming_recall_at_k(predictions, labels, k, ignore_mask=None,
Raises:
ValueError: If the dimensions of `predictions` and `labels` don't match or
if `weight` is not `None` and its shape doesn't match `predictions` or if
either `metrics_collections` or `updates_collections` are not a list or
tuple.
if `ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
"""
in_top_k = math_ops.to_float(nn.in_top_k(predictions, labels, k))
return streaming_mean(in_top_k, _mask_to_weights(ignore_mask),

View File

@ -713,6 +713,266 @@ class StreamingAUCTest(tf.test.TestCase):
self.assertAlmostEqual(expected_auc, auc.eval(), 2)
class StreamingPrecisionRecallThresholdsTest(tf.test.TestCase):
def setUp(self):
np.random.seed(1)
tf.reset_default_graph()
def testMetricsCollection(self):
my_collection_name = '__metrics__'
prec, _ = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions=tf.ones((10, 1)),
labels=tf.ones((10, 1)),
thresholds=[0, 0.5, 1.0],
metrics_collections=[my_collection_name])
rec, _ = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions=tf.ones((10, 1)),
labels=tf.ones((10, 1)),
thresholds=[0, 0.5, 1.0],
metrics_collections=[my_collection_name])
self.assertListEqual(tf.get_collection(my_collection_name), [prec, rec])
def testUpdatesCollection(self):
my_collection_name = '__updates__'
_, precision_op = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions=tf.ones((10, 1)),
labels=tf.ones((10, 1)),
thresholds=[0, 0.5, 1.0],
updates_collections=[my_collection_name])
_, recall_op = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions=tf.ones((10, 1)),
labels=tf.ones((10, 1)),
thresholds=[0, 0.5, 1.0],
updates_collections=[my_collection_name])
self.assertListEqual(tf.get_collection(my_collection_name),
[precision_op, recall_op])
def testValueTensorIsIdempotent(self):
predictions = tf.random_uniform((10, 3), maxval=1, dtype=tf.float32, seed=1)
labels = tf.random_uniform((10, 3), maxval=1, dtype=tf.int64, seed=1)
thresholds = [0, 0.5, 1.0]
prec, prec_op = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions, labels, thresholds)
rec, rec_op = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions, labels, thresholds)
with self.test_session() as sess:
sess.run(tf.initialize_local_variables())
# Run several updates, then verify idempotency.
sess.run([prec_op, rec_op])
initial_prec = prec.eval()
initial_rec = rec.eval()
for _ in range(10):
sess.run([prec_op, rec_op])
self.assertAllClose(initial_prec, prec.eval())
self.assertAllClose(initial_rec, rec.eval())
def testEffectivelyEquivalentShapes(self):
inputs = np.random.randint(0, 2, size=(100, 1))
with self.test_session() as sess:
predictions = tf.constant(inputs, dtype=tf.float32, shape=(100,))
labels = tf.constant(inputs, shape=(100, 1))
thresholds = [0.5]
prec, prec_op = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions, labels, thresholds)
rec, rec_op = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions, labels, thresholds)
sess.run(tf.initialize_local_variables())
sess.run([prec_op, rec_op])
self.assertEqual(1, prec.eval())
self.assertEqual(1, rec.eval())
def testAllCorrect(self):
inputs = np.random.randint(0, 2, size=(100, 1))
with self.test_session() as sess:
predictions = tf.constant(inputs, dtype=tf.float32)
labels = tf.constant(inputs)
thresholds = [0.5]
prec, prec_op = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions, labels, thresholds)
rec, rec_op = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions, labels, thresholds)
sess.run(tf.initialize_local_variables())
sess.run([prec_op, rec_op])
self.assertEqual(1, prec.eval())
self.assertEqual(1, rec.eval())
def testSomeCorrect(self):
with self.test_session() as sess:
predictions = tf.constant([1, 0, 1, 0], shape=(1, 4), dtype=tf.float32)
labels = tf.constant([0, 1, 1, 0], shape=(1, 4))
thresholds = [0.5]
prec, prec_op = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions, labels, thresholds)
rec, rec_op = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions, labels, thresholds)
sess.run(tf.initialize_local_variables())
sess.run([prec_op, rec_op])
self.assertAlmostEqual(0.5, prec.eval())
self.assertAlmostEqual(0.5, rec.eval())
def testAllIncorrect(self):
inputs = np.random.randint(0, 2, size=(100, 1))
with self.test_session() as sess:
predictions = tf.constant(inputs, dtype=tf.float32)
labels = tf.constant(1 - inputs, dtype=tf.float32)
thresholds = [0.5]
prec, prec_op = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions, labels, thresholds)
rec, rec_op = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions, labels, thresholds)
sess.run(tf.initialize_local_variables())
sess.run([prec_op, rec_op])
self.assertAlmostEqual(0, prec.eval())
self.assertAlmostEqual(0, rec.eval())
def testIgnoreMask(self):
with self.test_session() as sess:
predictions = tf.constant([[1, 0], [1, 0]], shape=(2, 2),
dtype=tf.float32)
labels = tf.constant([[0, 1], [1, 0]], shape=(2, 2))
ignore_mask = tf.constant([[True, True], [False, False]], shape=(2, 2))
thresholds = [0.5, 1.1]
prec, prec_op = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions, labels, thresholds, ignore_mask=ignore_mask)
rec, rec_op = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions, labels, thresholds, ignore_mask=ignore_mask)
[prec_low, prec_high] = tf.split(0, 2, prec)
prec_low = tf.reshape(prec_low, shape=())
prec_high = tf.reshape(prec_high, shape=())
[rec_low, rec_high] = tf.split(0, 2, rec)
rec_low = tf.reshape(rec_low, shape=())
rec_high = tf.reshape(rec_high, shape=())
sess.run(tf.initialize_local_variables())
sess.run([prec_op, rec_op])
self.assertAlmostEqual(1.0, prec_low.eval(), places=5)
self.assertAlmostEqual(0.0, prec_high.eval(), places=5)
self.assertAlmostEqual(1.0, rec_low.eval(), places=5)
self.assertAlmostEqual(0.0, rec_high.eval(), places=5)
def testExtremeThresholds(self):
with self.test_session() as sess:
predictions = tf.constant([1, 0, 1, 0], shape=(1, 4), dtype=tf.float32)
labels = tf.constant([0, 1, 1, 1], shape=(1, 4))
thresholds = [-1.0, 2.0] # lower/higher than any values
prec, prec_op = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions, labels, thresholds)
rec, rec_op = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions, labels, thresholds)
[prec_low, prec_high] = tf.split(0, 2, prec)
[rec_low, rec_high] = tf.split(0, 2, rec)
sess.run(tf.initialize_local_variables())
sess.run([prec_op, rec_op])
self.assertAlmostEqual(0.75, prec_low.eval())
self.assertAlmostEqual(0.0, prec_high.eval())
self.assertAlmostEqual(1.0, rec_low.eval())
self.assertAlmostEqual(0.0, rec_high.eval())
def testZeroLabelsPredictions(self):
with self.test_session() as sess:
predictions = tf.zeros([4], dtype=tf.float32)
labels = tf.zeros([4])
thresholds = [0.5]
prec, prec_op = tf.contrib.metrics.streaming_precision_at_thresholds(
predictions, labels, thresholds)
rec, rec_op = tf.contrib.metrics.streaming_recall_at_thresholds(
predictions, labels, thresholds)
sess.run(tf.initialize_local_variables())
sess.run([prec_op, rec_op])
self.assertAlmostEqual(0, prec.eval(), 6)
self.assertAlmostEqual(0, rec.eval(), 6)
def testWithMultipleUpdates(self):
num_samples = 5000
batch_size = 10
num_batches = num_samples / batch_size
# Create the labels and data.
labels = np.random.randint(0, 2, size=(num_samples, 1))
noise = np.random.normal(0.0, scale=0.2, size=(num_samples, 1))
predictions = 0.4 + 0.2 * labels + noise
predictions[predictions > 1] = 1
predictions[predictions < 0] = 0
thresholds = [0.3]
tp = 0
fp = 0
fn = 0
tn = 0
for i in range(num_samples):
if predictions[i] > thresholds[0]:
if labels[i] == 1:
tp += 1
else:
fp += 1
else:
if labels[i] == 1:
fn += 1
else:
tn += 1
epsilon = 1e-7
expected_prec = tp / (epsilon + tp + fp)
expected_rec = tp / (epsilon + tp + fn)
labels = labels.astype(np.float32)
predictions = predictions.astype(np.float32)
with self.test_session() as sess:
# Reshape the data so its easy to queue up:
predictions_batches = predictions.reshape((batch_size, num_batches))
labels_batches = labels.reshape((batch_size, num_batches))
# Enqueue the data:
predictions_queue = tf.FIFOQueue(num_batches, dtypes=tf.float32,
shapes=(batch_size,))
labels_queue = tf.FIFOQueue(num_batches, dtypes=tf.float32,
shapes=(batch_size,))
for i in range(int(num_batches)):
tf_prediction = tf.constant(predictions_batches[:, i])
tf_label = tf.constant(labels_batches[:, i])
sess.run([predictions_queue.enqueue(tf_prediction),
labels_queue.enqueue(tf_label)])
tf_predictions = predictions_queue.dequeue()
tf_labels = labels_queue.dequeue()
prec, prec_op = tf.contrib.metrics.streaming_precision_at_thresholds(
tf_predictions, tf_labels, thresholds)
rec, rec_op = tf.contrib.metrics.streaming_recall_at_thresholds(
tf_predictions, tf_labels, thresholds)
sess.run(tf.initialize_local_variables())
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.
# Although with higher number of samples/thresholds we should see the
# accuracy improving
self.assertAlmostEqual(expected_prec, prec.eval(), 2)
self.assertAlmostEqual(expected_rec, rec.eval(), 2)
class StreamingRecallAtKTest(tf.test.TestCase):
def setUp(self):

View File

@ -304,6 +304,7 @@ int DataTypeSize(DataType dt) {
return sizeof(T);
switch (dt) {
TF_CALL_POD_TYPES(CASE);
TF_CALL_QUANTIZED_TYPES(CASE);
default:
return 0;
}

View File

@ -50,10 +50,10 @@ namespace tensorflow {
// You call it like:
// GraphDefBuilder b;
// using namespace ::tensorflow::ops; // NOLINT(build/namespaces)
// Node* a = Const(7, b.opts());
// Node* na = Const(7, b.opts());
// // Note: WithName() returns a copy, opts is unchanged.
// Node* b = Const(5, b.opts().WithName("control-input"));
// Node* c = Identity(a, b.opts().WithControlInput(b));
// Node* nb = Const(5, b.opts().WithName("control-input"));
// Node* nc = Identity(na, b.opts().WithControlInput(nb));
// GraphDef graph_def;
// Status status = b.ToGraphDef(&graph_def);
// if (!status.ok()) { /* Handle error */ }

View File

@ -25,12 +25,12 @@ namespace tensorflow {
Tensor VecShape(int64 v) {
if (v >= std::numeric_limits<int32>::max()) {
Tensor shape(DT_INT32, TensorShape({1}));
Tensor shape(DT_INT64, TensorShape({1}));
shape.vec<int64>()(0) = v;
return shape;
} else {
Tensor shape(DT_INT64, TensorShape({1}));
shape.vec<int64>()(0) = v;
Tensor shape(DT_INT32, TensorShape({1}));
shape.vec<int32>()(0) = v;
return shape;
}
}

View File

@ -31,7 +31,6 @@ limitations under the License.
#include "tensorflow/core/kernels/concat_lib.h"
#include "tensorflow/core/kernels/split_lib.h"
#include "tensorflow/core/kernels/tensor_array.h"
#include "tensorflow/core/lib/core/refcount.h"
#include "tensorflow/core/lib/core/errors.h"
#include "tensorflow/core/lib/core/refcount.h"
#include "tensorflow/core/lib/strings/strcat.h"
@ -235,7 +234,7 @@ class TensorArrayGradOp : public TensorArrayCreationOp {
}
auto creator = [this, tensor_array, array_size,
tensor_array_output_handle](TensorArray** ret) {
tensor_array_output_handle](TensorArray** ret) -> Status {
*ret = new TensorArray(
tensor_array->ElemType(), *tensor_array_output_handle, array_size,
false /* dynamic_size */, true /* multiple_writes_aggregate */,

View File

@ -20,7 +20,7 @@ limitations under the License.
#include "tensorflow/core/platform/platform.h"
// Include appropriate platform-dependent implementations
#if defined(PLATFORM_GOOGLE)
#if defined(PLATFORM_GOOGLE) || defined(GOOGLE_INTEGRAL_TYPES)
#include "tensorflow/core/platform/google/integral_types.h"
#elif defined(PLATFORM_POSIX) || defined(PLATFORM_POSIX_ANDROID) || \
defined(PLATFORM_GOOGLE_ANDROID)

View File

@ -49,7 +49,7 @@ def conv_model(X, y):
features = tf.reshape(features, [-1, 12])
return learn.models.logistic_regression(features, y)
val_monitor = monitors.ValidationMonitor(X_val, y_val, n_classes=10, print_steps=50)
val_monitor = monitors.ValidationMonitor(X_val, y_val, every_n_steps=50)
# Create a classifier, train and predict.
classifier = learn.TensorFlowEstimator(model_fn=conv_model, n_classes=10,
steps=1000, learning_rate=0.05,

View File

@ -30,8 +30,7 @@ X_train, X_test, y_train, y_test = train_test_split(iris.data,
X_train, X_val, y_train, y_val = train_test_split(X_train, y_train,
test_size=0.2, random_state=42)
val_monitor = learn.monitors.ValidationMonitor(X_val, y_val,
early_stopping_rounds=200,
n_classes=3)
early_stopping_rounds=200)
# classifier with early stopping on training data
classifier1 = learn.TensorFlowDNNClassifier(hidden_units=[10, 20, 10],

View File

@ -219,10 +219,17 @@ Generate `n` samples.
Base class for continuous probability distributions.
`ContinuousDistribution` defines the API for the likelihood functions `pdf`
and `log_pdf` of continuous probability distributions.
and `log_pdf` of continuous probability distributions, and a property
`is_reparameterized` (returning `True` or `False`) which describes
whether the samples of this distribution are calculated in a differentiable
way from a non-parameterized distribution. For example, the `Normal`
distribution with parameters `mu` and `sigma` is reparameterized as
Subclasses must override both `pdf` and `log_pdf` but one can call this base
class's implementation.
```Normal(mu, sigma) = sigma * Normal(0, 1) + mu```
Subclasses must override `pdf` and `log_pdf` but one can call this base
class's implementation. They must also override the `is_reparameterized`
property.
See `BaseDistribution` for more information on the API for probability
distributions.
@ -300,6 +307,13 @@ Same meaning as `batch_shape`. May be only partially defined.
Same meaning as `event_shape`. May be only partially defined.
- - -
#### `tf.contrib.distributions.ContinuousDistribution.is_reparameterized` {#ContinuousDistribution.is_reparameterized}
- - -
#### `tf.contrib.distributions.ContinuousDistribution.log_cdf(value, name='log_cdf')` {#ContinuousDistribution.log_cdf}
@ -609,6 +623,13 @@ where digamma(alpha) is the digamma function.
- - -
#### `tf.contrib.distributions.Chi2.is_reparameterized` {#Chi2.is_reparameterized}
- - -
#### `tf.contrib.distributions.Chi2.log_cdf(x, name='log_cdf')` {#Chi2.log_cdf}
@ -798,6 +819,13 @@ where digamma(alpha) is the digamma function.
- - -
#### `tf.contrib.distributions.Exponential.is_reparameterized` {#Exponential.is_reparameterized}
- - -
#### `tf.contrib.distributions.Exponential.lam` {#Exponential.lam}
@ -871,20 +899,20 @@ Log pdf of observations in `x` under these Gamma distribution(s).
#### `tf.contrib.distributions.Exponential.sample(n, seed=None, name=None)` {#Exponential.sample}
Generate `n` samples.
Sample `n` observations from the Exponential Distributions.
##### Args:
* <b>`n`</b>: scalar. Number of samples to draw from each distribution.
* <b>`seed`</b>: Python integer seed for RNG
* <b>`name`</b>: name to give to the op.
* <b>`n`</b>: `Scalar`, type int32, the number of observations to sample.
* <b>`seed`</b>: Python integer, the random seed.
* <b>`name`</b>: The name to give this op.
##### Returns:
* <b>`samples`</b>: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape`
with values of type `self.dtype`.
* <b>`samples`</b>: `[n, ...]`, a `Tensor` of `n` samples for each
of the distributions determined by the hyperparameters.
- - -
@ -1025,6 +1053,13 @@ where digamma(alpha) is the digamma function.
- - -
#### `tf.contrib.distributions.Gamma.is_reparameterized` {#Gamma.is_reparameterized}
- - -
#### `tf.contrib.distributions.Gamma.log_cdf(x, name='log_cdf')` {#Gamma.log_cdf}
@ -1226,6 +1261,13 @@ The entropy of Gaussian distribution(s).
* <b>`entropy`</b>: tensor of dtype `dtype`, the entropy.
- - -
#### `tf.contrib.distributions.Gaussian.is_reparameterized` {#Gaussian.is_reparameterized}
- - -
#### `tf.contrib.distributions.Gaussian.log_cdf(x, name=None)` {#Gaussian.log_cdf}
@ -1465,6 +1507,13 @@ The entropy of Student t distribution(s).
- - -
#### `tf.contrib.distributions.StudentT.is_reparameterized` {#StudentT.is_reparameterized}
- - -
#### `tf.contrib.distributions.StudentT.log_cdf(value, name='log_cdf')` {#StudentT.log_cdf}
@ -1697,6 +1746,13 @@ The entropy of Uniform distribution(s).
- - -
#### `tf.contrib.distributions.Uniform.is_reparameterized` {#Uniform.is_reparameterized}
- - -
#### `tf.contrib.distributions.Uniform.log_cdf(x, name='log_cdf')` {#Uniform.log_cdf}
@ -1913,6 +1969,13 @@ The entropies of these Multivariate Normals.
* <b>`entropy`</b>: tensor of dtype `dtype`, the entropies.
- - -
#### `tf.contrib.distributions.MultivariateNormal.is_reparameterized` {#MultivariateNormal.is_reparameterized}
- - -
#### `tf.contrib.distributions.MultivariateNormal.log_pdf(x, name=None)` {#MultivariateNormal.log_pdf}

File diff suppressed because it is too large Load Diff

View File

@ -242,9 +242,9 @@ values in `ignore_mask` are `False`. In addition to performing the updates,
* <b>`ValueError`</b>: If the dimensions of `predictions` and `labels` don't match or
if `weight` is not `None` and its shape doesn't match `predictions` or
if either `metrics_collections` or `updates_collections` are not
a list or tuple.
if `ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
- - -
@ -295,9 +295,9 @@ values in `ignore_mask` are `False`. In addition to performing the updates,
* <b>`ValueError`</b>: If the dimensions of `predictions` and `labels` don't match or
if `weight` is not `None` and its shape doesn't match `predictions` or
if either `metrics_collections` or `updates_collections` are not
a list or tuple.
if `ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
- - -
@ -321,12 +321,12 @@ numbers of thresholds more closely approximating the true AUC.
To faciliate the estimation of the AUC over a stream of data, the function
creates an `update_op` operation whose behavior is dependent on the value of
`weights`. If `weights` is None, then `update_op` increments the
`ignore_mask`. If `ignore_mask` is None, then `update_op` increments the
`true_positives`, `true_negatives`, `false_positives` and `false_negatives`
counts with the number of each found in the current `predictions` and `labels`
`Tensors`. If `weights` is not `None`, then the increment is performed using
only the elements of `predictions` and `labels` whose corresponding value
in `ignore_mask` is `False`. In addition to performing the updates,
`Tensors`. If `ignore_mask` is not `None`, then the increment is performed
using only the elements of `predictions` and `labels` whose corresponding
value in `ignore_mask` is `False`. In addition to performing the updates,
`update_op` also returns the `auc`.
##### Args:
@ -347,7 +347,7 @@ in `ignore_mask` is `False`. In addition to performing the updates,
##### Returns:
* <b>`auc`</b>: A tensor representing the current area-under-curve.
* <b>`auc`</b>: A scalar tensor representing the current area-under-curve.
* <b>`update_op`</b>: An operation that increments the `true_positives`,
`true_negatives`, `false_positives` and `false_negatives` variables
appropriately and whose value matches `auc`.
@ -356,9 +356,9 @@ in `ignore_mask` is `False`. In addition to performing the updates,
* <b>`ValueError`</b>: If the shape of `predictions` and `labels` do not match or if
`weights` is not `None` and its shape doesn't match `values`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
`ignore_mask` is not `None` and its shape doesn't match `predictions` or
if either `metrics_collections` or `updates_collections` are not a list or
tuple.
- - -
@ -411,9 +411,9 @@ recall value.
* <b>`ValueError`</b>: If the dimensions of `predictions` and `labels` don't match or
if `weight` is not `None` and its shape doesn't match `predictions` or if
either `metrics_collections` or `updates_collections` are not a list or
tuple.
if `ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
- - -

View File

@ -100,6 +100,13 @@ where digamma(alpha) is the digamma function.
- - -
#### `tf.contrib.distributions.Chi2.is_reparameterized` {#Chi2.is_reparameterized}
- - -
#### `tf.contrib.distributions.Chi2.log_cdf(x, name='log_cdf')` {#Chi2.log_cdf}

View File

@ -1,10 +1,17 @@
Base class for continuous probability distributions.
`ContinuousDistribution` defines the API for the likelihood functions `pdf`
and `log_pdf` of continuous probability distributions.
and `log_pdf` of continuous probability distributions, and a property
`is_reparameterized` (returning `True` or `False`) which describes
whether the samples of this distribution are calculated in a differentiable
way from a non-parameterized distribution. For example, the `Normal`
distribution with parameters `mu` and `sigma` is reparameterized as
Subclasses must override both `pdf` and `log_pdf` but one can call this base
class's implementation.
```Normal(mu, sigma) = sigma * Normal(0, 1) + mu```
Subclasses must override `pdf` and `log_pdf` but one can call this base
class's implementation. They must also override the `is_reparameterized`
property.
See `BaseDistribution` for more information on the API for probability
distributions.
@ -82,6 +89,13 @@ Same meaning as `batch_shape`. May be only partially defined.
Same meaning as `event_shape`. May be only partially defined.
- - -
#### `tf.contrib.distributions.ContinuousDistribution.is_reparameterized` {#ContinuousDistribution.is_reparameterized}
- - -
#### `tf.contrib.distributions.ContinuousDistribution.log_cdf(value, name='log_cdf')` {#ContinuousDistribution.log_cdf}

View File

@ -93,6 +93,13 @@ where digamma(alpha) is the digamma function.
- - -
#### `tf.contrib.distributions.Exponential.is_reparameterized` {#Exponential.is_reparameterized}
- - -
#### `tf.contrib.distributions.Exponential.lam` {#Exponential.lam}
@ -166,20 +173,20 @@ Log pdf of observations in `x` under these Gamma distribution(s).
#### `tf.contrib.distributions.Exponential.sample(n, seed=None, name=None)` {#Exponential.sample}
Generate `n` samples.
Sample `n` observations from the Exponential Distributions.
##### Args:
* <b>`n`</b>: scalar. Number of samples to draw from each distribution.
* <b>`seed`</b>: Python integer seed for RNG
* <b>`name`</b>: name to give to the op.
* <b>`n`</b>: `Scalar`, type int32, the number of observations to sample.
* <b>`seed`</b>: Python integer, the random seed.
* <b>`name`</b>: The name to give this op.
##### Returns:
* <b>`samples`</b>: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape`
with values of type `self.dtype`.
* <b>`samples`</b>: `[n, ...]`, a `Tensor` of `n` samples for each
of the distributions determined by the hyperparameters.
- - -

View File

@ -124,6 +124,13 @@ where digamma(alpha) is the digamma function.
- - -
#### `tf.contrib.distributions.Gamma.is_reparameterized` {#Gamma.is_reparameterized}
- - -
#### `tf.contrib.distributions.Gamma.log_cdf(x, name='log_cdf')` {#Gamma.log_cdf}

View File

@ -105,6 +105,13 @@ The entropy of Gaussian distribution(s).
* <b>`entropy`</b>: tensor of dtype `dtype`, the entropy.
- - -
#### `tf.contrib.distributions.Gaussian.is_reparameterized` {#Gaussian.is_reparameterized}
- - -
#### `tf.contrib.distributions.Gaussian.log_cdf(x, name=None)` {#Gaussian.log_cdf}

View File

@ -125,6 +125,13 @@ The entropies of these Multivariate Normals.
* <b>`entropy`</b>: tensor of dtype `dtype`, the entropies.
- - -
#### `tf.contrib.distributions.MultivariateNormal.is_reparameterized` {#MultivariateNormal.is_reparameterized}
- - -
#### `tf.contrib.distributions.MultivariateNormal.log_pdf(x, name=None)` {#MultivariateNormal.log_pdf}

View File

@ -137,6 +137,13 @@ The entropy of Student t distribution(s).
- - -
#### `tf.contrib.distributions.StudentT.is_reparameterized` {#StudentT.is_reparameterized}
- - -
#### `tf.contrib.distributions.StudentT.log_cdf(value, name='log_cdf')` {#StudentT.log_cdf}

View File

@ -126,6 +126,13 @@ The entropy of Uniform distribution(s).
- - -
#### `tf.contrib.distributions.Uniform.is_reparameterized` {#Uniform.is_reparameterized}
- - -
#### `tf.contrib.distributions.Uniform.log_cdf(x, name='log_cdf')` {#Uniform.log_cdf}

View File

@ -12,7 +12,7 @@ Parameters:
model_dir: Directory to save model parameters, graph and etc.
- - -
#### `tf.contrib.learn.BaseEstimator.__init__(model_dir=None)` {#BaseEstimator.__init__}
#### `tf.contrib.learn.BaseEstimator.__init__(model_dir=None, config=None)` {#BaseEstimator.__init__}
@ -49,7 +49,7 @@ Evaluates given model with provided evaluation data.
- - -
#### `tf.contrib.learn.BaseEstimator.fit(x, y, steps, batch_size=32, monitor=None)` {#BaseEstimator.fit}
#### `tf.contrib.learn.BaseEstimator.fit(x, y, steps, batch_size=32, monitors=None)` {#BaseEstimator.fit}
Trains a model given training data X and y.
@ -64,8 +64,8 @@ Trains a model given training data X and y.
(class labels in classification, real numbers in regression).
* <b>`steps`</b>: number of steps to train model for.
* <b>`batch_size`</b>: minibatch size to use on the input, defaults to 32.
* <b>`monitor`</b>: monitor object to print training progress and invoke
early stopping.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
@ -92,7 +92,14 @@ params : mapping of string to any
- - -
#### `tf.contrib.learn.BaseEstimator.partial_fit(x, y, steps=1, batch_size=32, monitor=None)` {#BaseEstimator.partial_fit}
#### `tf.contrib.learn.BaseEstimator.model_dir` {#BaseEstimator.model_dir}
- - -
#### `tf.contrib.learn.BaseEstimator.partial_fit(x, y, steps=1, batch_size=32, monitors=None)` {#BaseEstimator.partial_fit}
Incremental fit on a batch of samples.
@ -115,8 +122,8 @@ to converge, and you want to split up training into subparts.
(class label in classification, real numbers in regression).
* <b>`steps`</b>: number of steps to train model for.
* <b>`batch_size`</b>: minibatch size to use on the input, defaults to 32.
* <b>`monitor`</b>: Monitor object to print training progress and invoke
early stopping.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
@ -151,7 +158,7 @@ Returns prediction probabilities for given features (classification).
* <b>`x`</b>: features.
* <b>`batch_size`</b>: OVerride default batch size.
* <b>`batch_size`</b>: Override default batch size.
##### Returns:
@ -176,7 +183,7 @@ self
- - -
#### `tf.contrib.learn.BaseEstimator.train(input_fn, steps, monitor=None)` {#BaseEstimator.train}
#### `tf.contrib.learn.BaseEstimator.train(input_fn, steps, monitors=None)` {#BaseEstimator.train}
Trains a model given input builder function.
@ -186,8 +193,8 @@ Trains a model given input builder function.
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitor`</b>: monitor object to print training progress and invoke
early stopping.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:

View File

@ -15,9 +15,10 @@ Parameters:
(like tf.train.GradientDescentOptimizer).
clip_gradients: clip_norm value for call to `clip_by_global_norm`. None
denotes no gradient clipping.
config: Configuration object.
- - -
#### `tf.contrib.learn.Estimator.__init__(model_fn=None, model_dir=None, classification=True, learning_rate=0.01, optimizer='SGD', clip_gradients=None)` {#Estimator.__init__}
#### `tf.contrib.learn.Estimator.__init__(model_fn=None, model_dir=None, classification=True, learning_rate=0.1, optimizer='Adagrad', clip_gradients=None, config=None)` {#Estimator.__init__}
@ -54,7 +55,7 @@ Evaluates given model with provided evaluation data.
- - -
#### `tf.contrib.learn.Estimator.fit(x, y, steps, batch_size=32, monitor=None)` {#Estimator.fit}
#### `tf.contrib.learn.Estimator.fit(x, y, steps, batch_size=32, monitors=None)` {#Estimator.fit}
Trains a model given training data X and y.
@ -69,8 +70,8 @@ Trains a model given training data X and y.
(class labels in classification, real numbers in regression).
* <b>`steps`</b>: number of steps to train model for.
* <b>`batch_size`</b>: minibatch size to use on the input, defaults to 32.
* <b>`monitor`</b>: monitor object to print training progress and invoke
early stopping.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
@ -97,7 +98,14 @@ params : mapping of string to any
- - -
#### `tf.contrib.learn.Estimator.partial_fit(x, y, steps=1, batch_size=32, monitor=None)` {#Estimator.partial_fit}
#### `tf.contrib.learn.Estimator.model_dir` {#Estimator.model_dir}
- - -
#### `tf.contrib.learn.Estimator.partial_fit(x, y, steps=1, batch_size=32, monitors=None)` {#Estimator.partial_fit}
Incremental fit on a batch of samples.
@ -120,8 +128,8 @@ to converge, and you want to split up training into subparts.
(class label in classification, real numbers in regression).
* <b>`steps`</b>: number of steps to train model for.
* <b>`batch_size`</b>: minibatch size to use on the input, defaults to 32.
* <b>`monitor`</b>: Monitor object to print training progress and invoke
early stopping.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
@ -156,7 +164,7 @@ Returns prediction probabilities for given features (classification).
* <b>`x`</b>: features.
* <b>`batch_size`</b>: OVerride default batch size.
* <b>`batch_size`</b>: Override default batch size.
##### Returns:
@ -181,7 +189,7 @@ self
- - -
#### `tf.contrib.learn.Estimator.train(input_fn, steps, monitor=None)` {#Estimator.train}
#### `tf.contrib.learn.Estimator.train(input_fn, steps, monitors=None)` {#Estimator.train}
Trains a model given input builder function.
@ -191,8 +199,8 @@ Trains a model given input builder function.
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitor`</b>: monitor object to print training progress and invoke
early stopping.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:

View File

@ -15,7 +15,14 @@ Returns weights of the linear classifier.
- - -
#### `tf.contrib.learn.TensorFlowClassifier.fit(X, y, monitor=None, logdir=None)` {#TensorFlowClassifier.fit}
#### `tf.contrib.learn.TensorFlowClassifier.evaluate(x=None, y=None, input_fn=None, steps=None)` {#TensorFlowClassifier.evaluate}
See base class.
- - -
#### `tf.contrib.learn.TensorFlowClassifier.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowClassifier.fit}
Builds a neural network model given provided `model_fn` and training
data X and y.
@ -29,7 +36,7 @@ To restart learning, create new estimator.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -37,8 +44,10 @@ To restart learning, create new estimator.
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early
stopping
* <b>`steps`</b>: int, number of steps to train.
If None or 0, train for `self.steps`.
* <b>`monitors`</b>: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
* <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization.
@ -110,7 +119,14 @@ Returns list of all variable names in this model.
- - -
#### `tf.contrib.learn.TensorFlowClassifier.partial_fit(X, y)` {#TensorFlowClassifier.partial_fit}
#### `tf.contrib.learn.TensorFlowClassifier.model_dir` {#TensorFlowClassifier.model_dir}
- - -
#### `tf.contrib.learn.TensorFlowClassifier.partial_fit(x, y)` {#TensorFlowClassifier.partial_fit}
Incremental fit on a batch of samples.
@ -125,7 +141,7 @@ to converge, and you want to split up training into subparts.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -140,7 +156,7 @@ to converge, and you want to split up training into subparts.
- - -
#### `tf.contrib.learn.TensorFlowClassifier.predict(X, axis=1, batch_size=None)` {#TensorFlowClassifier.predict}
#### `tf.contrib.learn.TensorFlowClassifier.predict(x, axis=1, batch_size=None)` {#TensorFlowClassifier.predict}
Predict class or regression for X.
@ -151,7 +167,7 @@ returned.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -168,14 +184,14 @@ returned.
- - -
#### `tf.contrib.learn.TensorFlowClassifier.predict_proba(X, batch_size=None)` {#TensorFlowClassifier.predict_proba}
#### `tf.contrib.learn.TensorFlowClassifier.predict_proba(x, batch_size=None)` {#TensorFlowClassifier.predict_proba}
Predict class probability of the input samples X.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`batch_size`</b>: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -260,6 +276,26 @@ Returns
self
- - -
#### `tf.contrib.learn.TensorFlowClassifier.train(input_fn, steps, monitors=None)` {#TensorFlowClassifier.train}
Trains a model given input builder function.
##### Args:
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
Returns self.
- - -
#### `tf.contrib.learn.TensorFlowClassifier.weights_` {#TensorFlowClassifier.weights_}

View File

@ -38,7 +38,14 @@ Returns bias of the DNN's bias layers.
- - -
#### `tf.contrib.learn.TensorFlowDNNClassifier.fit(X, y, monitor=None, logdir=None)` {#TensorFlowDNNClassifier.fit}
#### `tf.contrib.learn.TensorFlowDNNClassifier.evaluate(x=None, y=None, input_fn=None, steps=None)` {#TensorFlowDNNClassifier.evaluate}
See base class.
- - -
#### `tf.contrib.learn.TensorFlowDNNClassifier.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowDNNClassifier.fit}
Builds a neural network model given provided `model_fn` and training
data X and y.
@ -52,7 +59,7 @@ To restart learning, create new estimator.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -60,8 +67,10 @@ To restart learning, create new estimator.
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early
stopping
* <b>`steps`</b>: int, number of steps to train.
If None or 0, train for `self.steps`.
* <b>`monitors`</b>: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
* <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization.
@ -133,7 +142,14 @@ Returns list of all variable names in this model.
- - -
#### `tf.contrib.learn.TensorFlowDNNClassifier.partial_fit(X, y)` {#TensorFlowDNNClassifier.partial_fit}
#### `tf.contrib.learn.TensorFlowDNNClassifier.model_dir` {#TensorFlowDNNClassifier.model_dir}
- - -
#### `tf.contrib.learn.TensorFlowDNNClassifier.partial_fit(x, y)` {#TensorFlowDNNClassifier.partial_fit}
Incremental fit on a batch of samples.
@ -148,7 +164,7 @@ to converge, and you want to split up training into subparts.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -163,7 +179,7 @@ to converge, and you want to split up training into subparts.
- - -
#### `tf.contrib.learn.TensorFlowDNNClassifier.predict(X, axis=1, batch_size=None)` {#TensorFlowDNNClassifier.predict}
#### `tf.contrib.learn.TensorFlowDNNClassifier.predict(x, axis=1, batch_size=None)` {#TensorFlowDNNClassifier.predict}
Predict class or regression for X.
@ -174,7 +190,7 @@ returned.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -191,14 +207,14 @@ returned.
- - -
#### `tf.contrib.learn.TensorFlowDNNClassifier.predict_proba(X, batch_size=None)` {#TensorFlowDNNClassifier.predict_proba}
#### `tf.contrib.learn.TensorFlowDNNClassifier.predict_proba(x, batch_size=None)` {#TensorFlowDNNClassifier.predict_proba}
Predict class probability of the input samples X.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`batch_size`</b>: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -283,6 +299,26 @@ Returns
self
- - -
#### `tf.contrib.learn.TensorFlowDNNClassifier.train(input_fn, steps, monitors=None)` {#TensorFlowDNNClassifier.train}
Trains a model given input builder function.
##### Args:
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
Returns self.
- - -
#### `tf.contrib.learn.TensorFlowDNNClassifier.weights_` {#TensorFlowDNNClassifier.weights_}

View File

@ -38,7 +38,14 @@ Returns bias of the DNN's bias layers.
- - -
#### `tf.contrib.learn.TensorFlowDNNRegressor.fit(X, y, monitor=None, logdir=None)` {#TensorFlowDNNRegressor.fit}
#### `tf.contrib.learn.TensorFlowDNNRegressor.evaluate(x=None, y=None, input_fn=None, steps=None)` {#TensorFlowDNNRegressor.evaluate}
See base class.
- - -
#### `tf.contrib.learn.TensorFlowDNNRegressor.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowDNNRegressor.fit}
Builds a neural network model given provided `model_fn` and training
data X and y.
@ -52,7 +59,7 @@ To restart learning, create new estimator.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -60,8 +67,10 @@ To restart learning, create new estimator.
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early
stopping
* <b>`steps`</b>: int, number of steps to train.
If None or 0, train for `self.steps`.
* <b>`monitors`</b>: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
* <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization.
@ -133,7 +142,14 @@ Returns list of all variable names in this model.
- - -
#### `tf.contrib.learn.TensorFlowDNNRegressor.partial_fit(X, y)` {#TensorFlowDNNRegressor.partial_fit}
#### `tf.contrib.learn.TensorFlowDNNRegressor.model_dir` {#TensorFlowDNNRegressor.model_dir}
- - -
#### `tf.contrib.learn.TensorFlowDNNRegressor.partial_fit(x, y)` {#TensorFlowDNNRegressor.partial_fit}
Incremental fit on a batch of samples.
@ -148,7 +164,7 @@ to converge, and you want to split up training into subparts.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -163,7 +179,7 @@ to converge, and you want to split up training into subparts.
- - -
#### `tf.contrib.learn.TensorFlowDNNRegressor.predict(X, axis=1, batch_size=None)` {#TensorFlowDNNRegressor.predict}
#### `tf.contrib.learn.TensorFlowDNNRegressor.predict(x, axis=1, batch_size=None)` {#TensorFlowDNNRegressor.predict}
Predict class or regression for X.
@ -174,7 +190,7 @@ returned.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -191,14 +207,14 @@ returned.
- - -
#### `tf.contrib.learn.TensorFlowDNNRegressor.predict_proba(X, batch_size=None)` {#TensorFlowDNNRegressor.predict_proba}
#### `tf.contrib.learn.TensorFlowDNNRegressor.predict_proba(x, batch_size=None)` {#TensorFlowDNNRegressor.predict_proba}
Predict class probability of the input samples X.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`batch_size`</b>: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -287,6 +303,26 @@ Returns
self
- - -
#### `tf.contrib.learn.TensorFlowDNNRegressor.train(input_fn, steps, monitors=None)` {#TensorFlowDNNRegressor.train}
Trains a model given input builder function.
##### Args:
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
Returns self.
- - -
#### `tf.contrib.learn.TensorFlowDNNRegressor.weights_` {#TensorFlowDNNRegressor.weights_}

View File

@ -38,7 +38,14 @@ Parameters:
- - -
#### `tf.contrib.learn.TensorFlowEstimator.fit(X, y, monitor=None, logdir=None)` {#TensorFlowEstimator.fit}
#### `tf.contrib.learn.TensorFlowEstimator.evaluate(x=None, y=None, input_fn=None, steps=None)` {#TensorFlowEstimator.evaluate}
See base class.
- - -
#### `tf.contrib.learn.TensorFlowEstimator.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowEstimator.fit}
Builds a neural network model given provided `model_fn` and training
data X and y.
@ -52,7 +59,7 @@ To restart learning, create new estimator.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -60,8 +67,10 @@ To restart learning, create new estimator.
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early
stopping
* <b>`steps`</b>: int, number of steps to train.
If None or 0, train for `self.steps`.
* <b>`monitors`</b>: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
* <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization.
@ -133,7 +142,14 @@ Returns list of all variable names in this model.
- - -
#### `tf.contrib.learn.TensorFlowEstimator.partial_fit(X, y)` {#TensorFlowEstimator.partial_fit}
#### `tf.contrib.learn.TensorFlowEstimator.model_dir` {#TensorFlowEstimator.model_dir}
- - -
#### `tf.contrib.learn.TensorFlowEstimator.partial_fit(x, y)` {#TensorFlowEstimator.partial_fit}
Incremental fit on a batch of samples.
@ -148,7 +164,7 @@ to converge, and you want to split up training into subparts.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -163,7 +179,7 @@ to converge, and you want to split up training into subparts.
- - -
#### `tf.contrib.learn.TensorFlowEstimator.predict(X, axis=1, batch_size=None)` {#TensorFlowEstimator.predict}
#### `tf.contrib.learn.TensorFlowEstimator.predict(x, axis=1, batch_size=None)` {#TensorFlowEstimator.predict}
Predict class or regression for X.
@ -174,7 +190,7 @@ returned.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -191,14 +207,14 @@ returned.
- - -
#### `tf.contrib.learn.TensorFlowEstimator.predict_proba(X, batch_size=None)` {#TensorFlowEstimator.predict_proba}
#### `tf.contrib.learn.TensorFlowEstimator.predict_proba(x, batch_size=None)` {#TensorFlowEstimator.predict_proba}
Predict class probability of the input samples X.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`batch_size`</b>: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -256,3 +272,23 @@ Returns
self
- - -
#### `tf.contrib.learn.TensorFlowEstimator.train(input_fn, steps, monitors=None)` {#TensorFlowEstimator.train}
Trains a model given input builder function.
##### Args:
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
Returns self.

View File

@ -15,7 +15,14 @@ Returns weights of the linear classifier.
- - -
#### `tf.contrib.learn.TensorFlowLinearClassifier.fit(X, y, monitor=None, logdir=None)` {#TensorFlowLinearClassifier.fit}
#### `tf.contrib.learn.TensorFlowLinearClassifier.evaluate(x=None, y=None, input_fn=None, steps=None)` {#TensorFlowLinearClassifier.evaluate}
See base class.
- - -
#### `tf.contrib.learn.TensorFlowLinearClassifier.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowLinearClassifier.fit}
Builds a neural network model given provided `model_fn` and training
data X and y.
@ -29,7 +36,7 @@ To restart learning, create new estimator.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -37,8 +44,10 @@ To restart learning, create new estimator.
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early
stopping
* <b>`steps`</b>: int, number of steps to train.
If None or 0, train for `self.steps`.
* <b>`monitors`</b>: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
* <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization.
@ -110,7 +119,14 @@ Returns list of all variable names in this model.
- - -
#### `tf.contrib.learn.TensorFlowLinearClassifier.partial_fit(X, y)` {#TensorFlowLinearClassifier.partial_fit}
#### `tf.contrib.learn.TensorFlowLinearClassifier.model_dir` {#TensorFlowLinearClassifier.model_dir}
- - -
#### `tf.contrib.learn.TensorFlowLinearClassifier.partial_fit(x, y)` {#TensorFlowLinearClassifier.partial_fit}
Incremental fit on a batch of samples.
@ -125,7 +141,7 @@ to converge, and you want to split up training into subparts.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -140,7 +156,7 @@ to converge, and you want to split up training into subparts.
- - -
#### `tf.contrib.learn.TensorFlowLinearClassifier.predict(X, axis=1, batch_size=None)` {#TensorFlowLinearClassifier.predict}
#### `tf.contrib.learn.TensorFlowLinearClassifier.predict(x, axis=1, batch_size=None)` {#TensorFlowLinearClassifier.predict}
Predict class or regression for X.
@ -151,7 +167,7 @@ returned.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -168,14 +184,14 @@ returned.
- - -
#### `tf.contrib.learn.TensorFlowLinearClassifier.predict_proba(X, batch_size=None)` {#TensorFlowLinearClassifier.predict_proba}
#### `tf.contrib.learn.TensorFlowLinearClassifier.predict_proba(x, batch_size=None)` {#TensorFlowLinearClassifier.predict_proba}
Predict class probability of the input samples X.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`batch_size`</b>: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -260,6 +276,26 @@ Returns
self
- - -
#### `tf.contrib.learn.TensorFlowLinearClassifier.train(input_fn, steps, monitors=None)` {#TensorFlowLinearClassifier.train}
Trains a model given input builder function.
##### Args:
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
Returns self.
- - -
#### `tf.contrib.learn.TensorFlowLinearClassifier.weights_` {#TensorFlowLinearClassifier.weights_}

View File

@ -15,7 +15,14 @@ Returns bias of the linear regression.
- - -
#### `tf.contrib.learn.TensorFlowLinearRegressor.fit(X, y, monitor=None, logdir=None)` {#TensorFlowLinearRegressor.fit}
#### `tf.contrib.learn.TensorFlowLinearRegressor.evaluate(x=None, y=None, input_fn=None, steps=None)` {#TensorFlowLinearRegressor.evaluate}
See base class.
- - -
#### `tf.contrib.learn.TensorFlowLinearRegressor.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowLinearRegressor.fit}
Builds a neural network model given provided `model_fn` and training
data X and y.
@ -29,7 +36,7 @@ To restart learning, create new estimator.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -37,8 +44,10 @@ To restart learning, create new estimator.
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early
stopping
* <b>`steps`</b>: int, number of steps to train.
If None or 0, train for `self.steps`.
* <b>`monitors`</b>: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
* <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization.
@ -110,7 +119,14 @@ Returns list of all variable names in this model.
- - -
#### `tf.contrib.learn.TensorFlowLinearRegressor.partial_fit(X, y)` {#TensorFlowLinearRegressor.partial_fit}
#### `tf.contrib.learn.TensorFlowLinearRegressor.model_dir` {#TensorFlowLinearRegressor.model_dir}
- - -
#### `tf.contrib.learn.TensorFlowLinearRegressor.partial_fit(x, y)` {#TensorFlowLinearRegressor.partial_fit}
Incremental fit on a batch of samples.
@ -125,7 +141,7 @@ to converge, and you want to split up training into subparts.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -140,7 +156,7 @@ to converge, and you want to split up training into subparts.
- - -
#### `tf.contrib.learn.TensorFlowLinearRegressor.predict(X, axis=1, batch_size=None)` {#TensorFlowLinearRegressor.predict}
#### `tf.contrib.learn.TensorFlowLinearRegressor.predict(x, axis=1, batch_size=None)` {#TensorFlowLinearRegressor.predict}
Predict class or regression for X.
@ -151,7 +167,7 @@ returned.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -168,14 +184,14 @@ returned.
- - -
#### `tf.contrib.learn.TensorFlowLinearRegressor.predict_proba(X, batch_size=None)` {#TensorFlowLinearRegressor.predict_proba}
#### `tf.contrib.learn.TensorFlowLinearRegressor.predict_proba(x, batch_size=None)` {#TensorFlowLinearRegressor.predict_proba}
Predict class probability of the input samples X.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`batch_size`</b>: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -264,6 +280,26 @@ Returns
self
- - -
#### `tf.contrib.learn.TensorFlowLinearRegressor.train(input_fn, steps, monitors=None)` {#TensorFlowLinearRegressor.train}
Trains a model given input builder function.
##### Args:
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
Returns self.
- - -
#### `tf.contrib.learn.TensorFlowLinearRegressor.weights_` {#TensorFlowLinearRegressor.weights_}

View File

@ -48,7 +48,14 @@ Returns bias of the rnn layer.
- - -
#### `tf.contrib.learn.TensorFlowRNNClassifier.fit(X, y, monitor=None, logdir=None)` {#TensorFlowRNNClassifier.fit}
#### `tf.contrib.learn.TensorFlowRNNClassifier.evaluate(x=None, y=None, input_fn=None, steps=None)` {#TensorFlowRNNClassifier.evaluate}
See base class.
- - -
#### `tf.contrib.learn.TensorFlowRNNClassifier.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowRNNClassifier.fit}
Builds a neural network model given provided `model_fn` and training
data X and y.
@ -62,7 +69,7 @@ To restart learning, create new estimator.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -70,8 +77,10 @@ To restart learning, create new estimator.
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early
stopping
* <b>`steps`</b>: int, number of steps to train.
If None or 0, train for `self.steps`.
* <b>`monitors`</b>: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
* <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization.
@ -143,7 +152,14 @@ Returns list of all variable names in this model.
- - -
#### `tf.contrib.learn.TensorFlowRNNClassifier.partial_fit(X, y)` {#TensorFlowRNNClassifier.partial_fit}
#### `tf.contrib.learn.TensorFlowRNNClassifier.model_dir` {#TensorFlowRNNClassifier.model_dir}
- - -
#### `tf.contrib.learn.TensorFlowRNNClassifier.partial_fit(x, y)` {#TensorFlowRNNClassifier.partial_fit}
Incremental fit on a batch of samples.
@ -158,7 +174,7 @@ to converge, and you want to split up training into subparts.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -173,7 +189,7 @@ to converge, and you want to split up training into subparts.
- - -
#### `tf.contrib.learn.TensorFlowRNNClassifier.predict(X, axis=1, batch_size=None)` {#TensorFlowRNNClassifier.predict}
#### `tf.contrib.learn.TensorFlowRNNClassifier.predict(x, axis=1, batch_size=None)` {#TensorFlowRNNClassifier.predict}
Predict class or regression for X.
@ -184,7 +200,7 @@ returned.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -201,14 +217,14 @@ returned.
- - -
#### `tf.contrib.learn.TensorFlowRNNClassifier.predict_proba(X, batch_size=None)` {#TensorFlowRNNClassifier.predict_proba}
#### `tf.contrib.learn.TensorFlowRNNClassifier.predict_proba(x, batch_size=None)` {#TensorFlowRNNClassifier.predict_proba}
Predict class probability of the input samples X.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`batch_size`</b>: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -293,6 +309,26 @@ Returns
self
- - -
#### `tf.contrib.learn.TensorFlowRNNClassifier.train(input_fn, steps, monitors=None)` {#TensorFlowRNNClassifier.train}
Trains a model given input builder function.
##### Args:
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
Returns self.
- - -
#### `tf.contrib.learn.TensorFlowRNNClassifier.weights_` {#TensorFlowRNNClassifier.weights_}

View File

@ -48,7 +48,14 @@ Returns bias of the rnn layer.
- - -
#### `tf.contrib.learn.TensorFlowRNNRegressor.fit(X, y, monitor=None, logdir=None)` {#TensorFlowRNNRegressor.fit}
#### `tf.contrib.learn.TensorFlowRNNRegressor.evaluate(x=None, y=None, input_fn=None, steps=None)` {#TensorFlowRNNRegressor.evaluate}
See base class.
- - -
#### `tf.contrib.learn.TensorFlowRNNRegressor.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowRNNRegressor.fit}
Builds a neural network model given provided `model_fn` and training
data X and y.
@ -62,7 +69,7 @@ To restart learning, create new estimator.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -70,8 +77,10 @@ To restart learning, create new estimator.
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early
stopping
* <b>`steps`</b>: int, number of steps to train.
If None or 0, train for `self.steps`.
* <b>`monitors`</b>: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
* <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization.
@ -143,7 +152,14 @@ Returns list of all variable names in this model.
- - -
#### `tf.contrib.learn.TensorFlowRNNRegressor.partial_fit(X, y)` {#TensorFlowRNNRegressor.partial_fit}
#### `tf.contrib.learn.TensorFlowRNNRegressor.model_dir` {#TensorFlowRNNRegressor.model_dir}
- - -
#### `tf.contrib.learn.TensorFlowRNNRegressor.partial_fit(x, y)` {#TensorFlowRNNRegressor.partial_fit}
Incremental fit on a batch of samples.
@ -158,7 +174,7 @@ to converge, and you want to split up training into subparts.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -173,7 +189,7 @@ to converge, and you want to split up training into subparts.
- - -
#### `tf.contrib.learn.TensorFlowRNNRegressor.predict(X, axis=1, batch_size=None)` {#TensorFlowRNNRegressor.predict}
#### `tf.contrib.learn.TensorFlowRNNRegressor.predict(x, axis=1, batch_size=None)` {#TensorFlowRNNRegressor.predict}
Predict class or regression for X.
@ -184,7 +200,7 @@ returned.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -201,14 +217,14 @@ returned.
- - -
#### `tf.contrib.learn.TensorFlowRNNRegressor.predict_proba(X, batch_size=None)` {#TensorFlowRNNRegressor.predict_proba}
#### `tf.contrib.learn.TensorFlowRNNRegressor.predict_proba(x, batch_size=None)` {#TensorFlowRNNRegressor.predict_proba}
Predict class probability of the input samples X.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`batch_size`</b>: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -297,6 +313,26 @@ Returns
self
- - -
#### `tf.contrib.learn.TensorFlowRNNRegressor.train(input_fn, steps, monitors=None)` {#TensorFlowRNNRegressor.train}
Trains a model given input builder function.
##### Args:
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
Returns self.
- - -
#### `tf.contrib.learn.TensorFlowRNNRegressor.weights_` {#TensorFlowRNNRegressor.weights_}

View File

@ -15,7 +15,14 @@ Returns bias of the linear regression.
- - -
#### `tf.contrib.learn.TensorFlowRegressor.fit(X, y, monitor=None, logdir=None)` {#TensorFlowRegressor.fit}
#### `tf.contrib.learn.TensorFlowRegressor.evaluate(x=None, y=None, input_fn=None, steps=None)` {#TensorFlowRegressor.evaluate}
See base class.
- - -
#### `tf.contrib.learn.TensorFlowRegressor.fit(x, y, steps=None, monitors=None, logdir=None)` {#TensorFlowRegressor.fit}
Builds a neural network model given provided `model_fn` and training
data X and y.
@ -29,7 +36,7 @@ To restart learning, create new estimator.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -37,8 +44,10 @@ To restart learning, create new estimator.
iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early
stopping
* <b>`steps`</b>: int, number of steps to train.
If None or 0, train for `self.steps`.
* <b>`monitors`</b>: List of `BaseMonitor` objects to print training progress and
invoke early stopping.
* <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization.
@ -110,7 +119,14 @@ Returns list of all variable names in this model.
- - -
#### `tf.contrib.learn.TensorFlowRegressor.partial_fit(X, y)` {#TensorFlowRegressor.partial_fit}
#### `tf.contrib.learn.TensorFlowRegressor.model_dir` {#TensorFlowRegressor.model_dir}
- - -
#### `tf.contrib.learn.TensorFlowRegressor.partial_fit(x, y)` {#TensorFlowRegressor.partial_fit}
Incremental fit on a batch of samples.
@ -125,7 +141,7 @@ to converge, and you want to split up training into subparts.
##### Args:
* <b>`X`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
* <b>`x`</b>: matrix or tensor of shape [n_samples, n_features...]. Can be
iterator that returns arrays of features. The training input
samples for fitting the model.
@ -140,7 +156,7 @@ to converge, and you want to split up training into subparts.
- - -
#### `tf.contrib.learn.TensorFlowRegressor.predict(X, axis=1, batch_size=None)` {#TensorFlowRegressor.predict}
#### `tf.contrib.learn.TensorFlowRegressor.predict(x, axis=1, batch_size=None)` {#TensorFlowRegressor.predict}
Predict class or regression for X.
@ -151,7 +167,7 @@ returned.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used.
Use 2 for sequence predictions.
@ -168,14 +184,14 @@ returned.
- - -
#### `tf.contrib.learn.TensorFlowRegressor.predict_proba(X, batch_size=None)` {#TensorFlowRegressor.predict_proba}
#### `tf.contrib.learn.TensorFlowRegressor.predict_proba(x, batch_size=None)` {#TensorFlowRegressor.predict_proba}
Predict class probability of the input samples X.
##### Args:
* <b>`X`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`x`</b>: array-like matrix, [n_samples, n_features...] or iterator.
* <b>`batch_size`</b>: If test set is too big, use batch size to split
it into mini batches. By default the batch_size member variable is used.
@ -264,6 +280,26 @@ Returns
self
- - -
#### `tf.contrib.learn.TensorFlowRegressor.train(input_fn, steps, monitors=None)` {#TensorFlowRegressor.train}
Trains a model given input builder function.
##### Args:
* <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor.
* <b>`steps`</b>: number of steps to train model for.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:
Returns self.
- - -
#### `tf.contrib.learn.TensorFlowRegressor.weights_` {#TensorFlowRegressor.weights_}

View File

@ -1,4 +1,4 @@
### `tf.contrib.learn.train(graph, output_dir, train_op, loss_op, global_step_tensor=None, init_op=None, init_fn=None, log_every_steps=10, supervisor_is_chief=True, supervisor_master='', supervisor_save_model_secs=600, supervisor_save_summaries_secs=10, feed_fn=None, max_steps=None, fail_on_nan_loss=True)` {#train}
### `tf.contrib.learn.train(graph, output_dir, train_op, loss_op, global_step_tensor=None, init_op=None, init_feed_dict=None, init_fn=None, log_every_steps=10, supervisor_is_chief=True, supervisor_master='', supervisor_save_model_secs=600, supervisor_save_summaries_steps=100, feed_fn=None, max_steps=None, fail_on_nan_loss=True, monitors=None)` {#train}
Train a model.
@ -27,6 +27,8 @@ program is terminated with exit code 1.
one is extracted from the graph using the same logic as in `Supervisor`.
* <b>`init_op`</b>: An op that initializes the graph. If `None`, use `Supervisor`'s
default.
* <b>`init_feed_dict`</b>: A dictionary that maps `Tensor` objects to feed values.
This feed dictionary will be used when `init_op` is evaluated.
* <b>`init_fn`</b>: Optional callable passed to Supervisor to initialize the model.
* <b>`log_every_steps`</b>: Output logs regularly. The logs contain timing data and the
current loss.
@ -35,13 +37,15 @@ program is terminated with exit code 1.
* <b>`supervisor_master`</b>: The master string to use when preparing the session.
* <b>`supervisor_save_model_secs`</b>: Save a checkpoint every
`supervisor_save_model_secs` seconds when training.
* <b>`supervisor_save_summaries_secs`</b>: Save summaries every
`supervisor_save_summaries_secs` seconds when training.
* <b>`supervisor_save_summaries_steps`</b>: Save summaries every
`supervisor_save_summaries_steps` seconds when training.
* <b>`feed_fn`</b>: A function that is called every iteration to produce a `feed_dict`
passed to `session.run` calls. Optional.
* <b>`max_steps`</b>: Train until `global_step_tensor` evaluates to this value.
* <b>`fail_on_nan_loss`</b>: If true, raise `NanLossDuringTrainingError` if `loss_op`
evaluates to `NaN`. If false, continue training as if nothing happened.
* <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
inside the training loop.
##### Returns:

View File

@ -17,12 +17,12 @@ numbers of thresholds more closely approximating the true AUC.
To faciliate the estimation of the AUC over a stream of data, the function
creates an `update_op` operation whose behavior is dependent on the value of
`weights`. If `weights` is None, then `update_op` increments the
`ignore_mask`. If `ignore_mask` is None, then `update_op` increments the
`true_positives`, `true_negatives`, `false_positives` and `false_negatives`
counts with the number of each found in the current `predictions` and `labels`
`Tensors`. If `weights` is not `None`, then the increment is performed using
only the elements of `predictions` and `labels` whose corresponding value
in `ignore_mask` is `False`. In addition to performing the updates,
`Tensors`. If `ignore_mask` is not `None`, then the increment is performed
using only the elements of `predictions` and `labels` whose corresponding
value in `ignore_mask` is `False`. In addition to performing the updates,
`update_op` also returns the `auc`.
##### Args:
@ -43,7 +43,7 @@ in `ignore_mask` is `False`. In addition to performing the updates,
##### Returns:
* <b>`auc`</b>: A tensor representing the current area-under-curve.
* <b>`auc`</b>: A scalar tensor representing the current area-under-curve.
* <b>`update_op`</b>: An operation that increments the `true_positives`,
`true_negatives`, `false_positives` and `false_negatives` variables
appropriately and whose value matches `auc`.
@ -52,7 +52,7 @@ in `ignore_mask` is `False`. In addition to performing the updates,
* <b>`ValueError`</b>: If the shape of `predictions` and `labels` do not match or if
`weights` is not `None` and its shape doesn't match `values`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.
`ignore_mask` is not `None` and its shape doesn't match `predictions` or
if either `metrics_collections` or `updates_collections` are not a list or
tuple.

View File

@ -44,7 +44,7 @@ values in `ignore_mask` are `False`. In addition to performing the updates,
* <b>`ValueError`</b>: If the dimensions of `predictions` and `labels` don't match or
if `weight` is not `None` and its shape doesn't match `predictions` or
if either `metrics_collections` or `updates_collections` are not
a list or tuple.
if `ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.

View File

@ -44,7 +44,7 @@ values in `ignore_mask` are `False`. In addition to performing the updates,
* <b>`ValueError`</b>: If the dimensions of `predictions` and `labels` don't match or
if `weight` is not `None` and its shape doesn't match `predictions` or
if either `metrics_collections` or `updates_collections` are not
a list or tuple.
if `ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.

View File

@ -46,7 +46,7 @@ recall value.
* <b>`ValueError`</b>: If the dimensions of `predictions` and `labels` don't match or
if `weight` is not `None` and its shape doesn't match `predictions` or if
either `metrics_collections` or `updates_collections` are not a list or
tuple.
if `ignore_mask` is not `None` and its shape doesn't match `predictions`
or if either `metrics_collections` or `updates_collections` are not a list
or tuple.

View File

@ -1,4 +1,4 @@
### `tf.make_template(name_, func_, **kwargs)` {#make_template}
### `tf.make_template(name_, func_, create_scope_now_=False, **kwargs)` {#make_template}
Given an arbitrary function, wrap it so that it does variable sharing.
@ -68,10 +68,14 @@ with tf.variable_scope(vs, reuse=True):
w2 = scale_by_y2(input2)
```
Note: The full variable scope is captured at the time of the first call.
Depending on the value of `create_scope_now_`, the full variable scope may be
captured either at the time of first call or at the time of construction. If
this option is set to True, then all Tensors created by repeated calls to the
template will have an extra trailing _N+1 to their name, as the first time the
scope is entered in the Template constructor no Tensors are created.
Note: `name_` and `func_` have a following underscore to reduce the likelihood
of collisions with kwargs.
Note: `name_`, `func_` and `create_scope_now_` have a trailing underscore to
reduce the likelihood of collisions with kwargs.
##### Args:
@ -79,14 +83,20 @@ of collisions with kwargs.
* <b>`name_`</b>: A name for the scope created by this template. If necessary, the name
will be made unique by appending `_N` to the name.
* <b>`func_`</b>: The function to wrap.
* <b>`create_scope_now_`</b>: Boolean controlling whether the scope should be created
when the template is constructed or when the template is called. Default
is False, meaning the scope is created when the template is called.
* <b>`**kwargs`</b>: Keyword arguments to apply to `func_`.
##### Returns:
A function that will enter a `variable_scope` before calling `func_`. The
first time it is called, it will create a non-reusing scope so that the
variables will be unique. On each subsequent call, it will reuse those
variables.
A function to encapsulate a set of variables which should be created once
and reused. An enclosing scope will created, either where `make_template`
is called, or wherever the result is called, depending on the value of
`create_scope_now_`. Regardless of the value, the first time the template
is called it will enter the scope with no reuse, and call `func_` to create
variables, which are guaranteed to be unique. All subsequent calls will
re-enter the scope and reuse those variables.
##### Raises:

View File

@ -11,6 +11,6 @@ Merges all summaries collected in the default graph.
##### Returns:
If no summaries were collected, returns None. Otherwise returns a scalar
`Tensor` of type`string` containing the serialized `Summary` protocol
`Tensor` of type `string` containing the serialized `Summary` protocol
buffer resulting from the merging.

View File

@ -1,4 +1,4 @@
### `tf.nn.sufficient_statistics(x, axes, shift=True, keep_dims=False, name=None)` {#sufficient_statistics}
### `tf.nn.sufficient_statistics(x, axes, shift=False, keep_dims=False, name=None)` {#sufficient_statistics}
Calculate the sufficient statistics for the mean and variance of `x`.
@ -6,6 +6,9 @@ These sufficient statistics are computed using the one pass algorithm on
an input that's optionally shifted using the value of the 1st element in `x`.
See:
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Computing_shifted_data
Unfortunately, in some cases using a random individual sample as the shift
value leads experimentally to very poor numerical stability, so it is disabled
by default. The one-pass approach might have to be revised accordingly.
##### Args:

View File

@ -1,6 +1,6 @@
### `tf.train.write_graph(graph_def, logdir, name, as_text=True)` {#write_graph}
Writes a graph proto on disk.
Writes a graph proto to a file.
The graph is written as a binary proto unless `as_text` is `True`.
@ -14,7 +14,8 @@ tf.train.write_graph(sess.graph_def, '/tmp/my-model', 'train.pbtxt')
* <b>`graph_def`</b>: A `GraphDef` protocol buffer.
* <b>`logdir`</b>: Directory where to write the graph.
* <b>`logdir`</b>: Directory where to write the graph. This can refer to remote
filesystems, such as Google Cloud Storage (GCS).
* <b>`name`</b>: Filename for the graph.
* <b>`as_text`</b>: If `True`, writes the graph as an ASCII proto.

View File

@ -824,7 +824,7 @@ convolutional neural networks (NIPS 2012)]
- - -
### `tf.nn.sufficient_statistics(x, axes, shift=True, keep_dims=False, name=None)` {#sufficient_statistics}
### `tf.nn.sufficient_statistics(x, axes, shift=False, keep_dims=False, name=None)` {#sufficient_statistics}
Calculate the sufficient statistics for the mean and variance of `x`.
@ -832,6 +832,9 @@ These sufficient statistics are computed using the one pass algorithm on
an input that's optionally shifted using the value of the 1st element in `x`.
See:
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Computing_shifted_data
Unfortunately, in some cases using a random individual sample as the shift
value leads experimentally to very poor numerical stability, so it is disabled
by default. The one-pass approach might have to be revised accordingly.
##### Args:

View File

@ -1395,7 +1395,7 @@ Returns the current variable scope.
- - -
### `tf.make_template(name_, func_, **kwargs)` {#make_template}
### `tf.make_template(name_, func_, create_scope_now_=False, **kwargs)` {#make_template}
Given an arbitrary function, wrap it so that it does variable sharing.
@ -1465,10 +1465,14 @@ with tf.variable_scope(vs, reuse=True):
w2 = scale_by_y2(input2)
```
Note: The full variable scope is captured at the time of the first call.
Depending on the value of `create_scope_now_`, the full variable scope may be
captured either at the time of first call or at the time of construction. If
this option is set to True, then all Tensors created by repeated calls to the
template will have an extra trailing _N+1 to their name, as the first time the
scope is entered in the Template constructor no Tensors are created.
Note: `name_` and `func_` have a following underscore to reduce the likelihood
of collisions with kwargs.
Note: `name_`, `func_` and `create_scope_now_` have a trailing underscore to
reduce the likelihood of collisions with kwargs.
##### Args:
@ -1476,14 +1480,20 @@ of collisions with kwargs.
* <b>`name_`</b>: A name for the scope created by this template. If necessary, the name
will be made unique by appending `_N` to the name.
* <b>`func_`</b>: The function to wrap.
* <b>`create_scope_now_`</b>: Boolean controlling whether the scope should be created
when the template is constructed or when the template is called. Default
is False, meaning the scope is created when the template is called.
* <b>`**kwargs`</b>: Keyword arguments to apply to `func_`.
##### Returns:
A function that will enter a `variable_scope` before calling `func_`. The
first time it is called, it will create a non-reusing scope so that the
variables will be unique. On each subsequent call, it will reuse those
variables.
A function to encapsulate a set of variables which should be created once
and reused. An enclosing scope will created, either where `make_template`
is called, or wherever the result is called, depending on the value of
`create_scope_now_`. Regardless of the value, the first time the template
is called it will enter the scope with no reuse, and call `func_` to create
variables, which are guaranteed to be unique. All subsequent calls will
re-enter the scope and reuse those variables.
##### Raises:

View File

@ -3078,7 +3078,7 @@ Merges all summaries collected in the default graph.
##### Returns:
If no summaries were collected, returns None. Otherwise returns a scalar
`Tensor` of type`string` containing the serialized `Summary` protocol
`Tensor` of type `string` containing the serialized `Summary` protocol
buffer resulting from the merging.
@ -3346,7 +3346,7 @@ global_step: 10
### `tf.train.write_graph(graph_def, logdir, name, as_text=True)` {#write_graph}
Writes a graph proto on disk.
Writes a graph proto to a file.
The graph is written as a binary proto unless `as_text` is `True`.
@ -3360,7 +3360,8 @@ tf.train.write_graph(sess.graph_def, '/tmp/my-model', 'train.pbtxt')
* <b>`graph_def`</b>: A `GraphDef` protocol buffer.
* <b>`logdir`</b>: Directory where to write the graph.
* <b>`logdir`</b>: Directory where to write the graph. This can refer to remote
filesystems, such as Google Cloud Storage (GCS).
* <b>`name`</b>: Filename for the graph.
* <b>`as_text`</b>: If `True`, writes the graph as an ASCII proto.

View File

@ -92,8 +92,8 @@ creates a part of the graph and returns output tensors.
If operation needs to save some `Tensor`s to Graph collections,
put the arguments with names of the collections right before `name` argument.
* Tensor arguments should be either a single tensor or an iterable of tensors.
*Not a "Tensor or list of Tensors".*
* Tensor arguments should be either a single tensor or an iterable of tensors,
not both. E.g. a "Tensor or list of Tensors" is too broad.
* Operations that take tensors as arguments should call `convert_to_tensor`
to convert non-tensor inputs into tensors if they are using C++ operations.

View File

@ -15,6 +15,7 @@ load("//tensorflow:tensorflow.bzl", "cuda_py_test")
load("//tensorflow:tensorflow.bzl", "cuda_py_tests")
load("//tensorflow/core:platform/default/build_config.bzl", "tf_proto_library")
load("//tensorflow/core:platform/default/build_config.bzl", "tf_proto_library_py")
load("//tensorflow/core:platform/default/build_config.bzl", "tf_additional_lib_deps")
py_library(
name = "python",
@ -983,6 +984,7 @@ tf_py_wrap_cc(
"lib/io/py_record_writer.i",
"platform/base.i",
"platform/numpy.i",
"training/saver_io.i",
"training/server_lib.i",
"util/port.i",
"util/py_checkpoint_reader.i",
@ -994,12 +996,12 @@ tf_py_wrap_cc(
":py_record_writer_lib",
":python_op_gen",
":tf_session_helper",
"//tensorflow/core:lib",
"//tensorflow/core/distributed_runtime:server_lib",
"//tensorflow/core/distributed_runtime/rpc:grpc_server_lib",
"//tensorflow/core/distributed_runtime/rpc:grpc_session",
"//tensorflow/core:lib",
"//tensorflow/core/distributed_runtime:server_lib",
"//util/python:python_headers",
],
] + tf_additional_lib_deps(),
)
py_library(

View File

@ -1256,17 +1256,50 @@ class ControlFlowTest(tf.test.TestCase):
def break_run_twice(ix):
def _break():
assert not ran_once[ix]
ran_once[ix] = True
return tf.constant(ix)
return _break
# Should not fail - each conditional gets called exactly once
# except default. Default gets called twice: once to create an
# empty output and once for the actual cond switch.
r6 = tf.case([(x < y, break_run_twice(0)), (x > y, break_run_twice(1))],
default=break_run_twice(2))
default=lambda: tf.constant(2))
self.assertAllEqual(r6.eval(), 0)
def testCaseSideEffects(self):
with self.test_session() as sess:
v0 = tf.Variable(-1)
v1 = tf.Variable(-1)
v2 = tf.Variable(-1)
a = lambda: control_flow_ops.with_dependencies([tf.assign(v0, 0)], 0)
b = lambda: control_flow_ops.with_dependencies([tf.assign(v1, 1)], 1)
c = lambda: control_flow_ops.with_dependencies([tf.assign(v2, 2)], 2)
x = tf.constant(1)
y = tf.constant(2)
r0 = tf.case(((x < y, a), (x > y, b)), default=c, exclusive=True)
r1 = tf.case(((x > y, a), (x < y, b)), default=c, exclusive=True)
r2 = tf.case(((x > y, a), (x > y, b)), default=c, exclusive=True)
tf.initialize_all_variables().run()
self.assertAllEqual(sess.run([v0, v1, v2]), [-1] * 3)
self.assertEqual(2, r2.eval())
self.assertAllEqual(sess.run([v0, v1, v2]), [-1, -1, 2])
tf.initialize_all_variables().run()
self.assertAllEqual(sess.run([v0, v1, v2]), [-1] * 3)
self.assertEqual(1, r1.eval())
self.assertAllEqual(sess.run([v0, v1, v2]), [-1, 1, -1])
tf.initialize_all_variables().run()
self.assertAllEqual(sess.run([v0, v1, v2]), [-1] * 3)
self.assertEqual(0, r0.eval())
self.assertAllEqual(sess.run([v0, v1, v2]), [0, -1, -1])
def testOneOpCond(self):
with self.test_session():
v = tf.Variable(0)

View File

@ -206,6 +206,27 @@ class TemplateTest(tf.test.TestCase):
self.assertEqual("s1/nested_1/dummy:0", v1.name)
self.assertEqual("s1_2/nested_1/dummy:0", v3.name)
def test_immediate_scope_creation(self):
# Create templates in scope a then call in scope b. make_template should
# capture the scope the first time it is called, and make_immediate_template
# should capture the scope at construction time.
with tf.variable_scope("ctor_scope"):
tmpl_immed = template.make_template(
"a", var_scoped_function, True) # create scope here
tmpl_defer = template.make_template(
"b", var_scoped_function, False) # default: create scope at __call__
with tf.variable_scope("call_scope"):
inner_imm_var = tmpl_immed()
inner_defer_var = tmpl_defer()
outer_imm_var = tmpl_immed()
outer_defer_var = tmpl_defer()
self.assertNotEqual(inner_imm_var, inner_defer_var)
self.assertEqual(outer_imm_var, inner_imm_var)
self.assertEqual(outer_defer_var, inner_defer_var)
self.assertEqual("ctor_scope/a/dummy:0", inner_imm_var.name)
self.assertEqual("call_scope/b/dummy:0", inner_defer_var.name)
if __name__ == "__main__":
tf.test.main()

View File

@ -69,8 +69,8 @@ bool _BytesToStringPiece(PyObject* obj, tensorflow::StringPiece* result) {
$1 = &temp;
}
// C++ functions returning tensorflow::StringPiece will simply return bytes in Python,
// or None if the StringPiece contained a NULL pointer.
// C++ functions returning tensorflow::StringPiece will simply return bytes in
// Python, or None if the StringPiece contained a NULL pointer.
%typemap(out) tensorflow::StringPiece {
if ($1.data()) {
$result = PyBytes_FromStringAndSize($1.data(), $1.size());
@ -79,3 +79,30 @@ bool _BytesToStringPiece(PyObject* obj, tensorflow::StringPiece* result) {
$result = Py_None;
}
}
// Converts a C++ string vector to a Python string list.
%typemap(out) std::vector<string> {
const int size = $1.size();
auto temp_string_list = tensorflow::make_safe(PyList_New(size));
if (!temp_string_list) {
SWIG_fail;
}
tensorflow::Safe_PyObjectVector converted;
converted.reserve(size);
for (const string& op : $1) {
%#if PY_MAJOR_VERSION >= 3
PyObject* py_str = PyUnicode_FromStringAndSize(op.data(), op.size());
%#else
PyObject* py_str = PyString_FromStringAndSize(op.data(), op.size());
%#endif
if (!py_str) {
SWIG_fail;
}
converted.emplace_back(tensorflow::make_safe(py_str));
}
for (int i = 0; i < converted.size(); ++i) {
PyList_SET_ITEM(temp_string_list.get(), i, converted[i].release());
}
$result = temp_string_list.release();
}

View File

@ -1985,29 +1985,64 @@ def case(pred_fn_pairs, default, exclusive=False, name="case"):
for i, p in enumerate(preds):
with ops.name_scope("not_%d" % i):
not_preds.append(math_ops.logical_not(p))
and_not_preds = [constant_op.constant(True, name="and_not_true")]
for i, notp in enumerate(not_preds[:-1]):
and_not_preds = [constant_op.constant(True, name="always_true")]
for i, notp in enumerate(not_preds):
with ops.name_scope("and_not_%d" % i):
and_not_preds.append(math_ops.logical_and(and_not_preds[-1], notp))
# preds = [p1, p2, p3]
# fns = [f1, f2, f3]
# not_preds = [~p1, ~p2, ~p3]
# case_preds = [p1 & True,
# and_not_preds = [True, ~p1, ~p1 & ~p2, ~p1 & ~p2 & ~p3]
# case_preds = [p1,
# p2 & ~p1,
# p3 & ~p1 & ~ p2]
# p3 & ~p2 & ~p1,
# ~p3 & ~p2 & ~p1]
case_preds = []
for i, (p, and_not_p_prev) in enumerate(zip(preds, and_not_preds)):
for i, (p, and_not_p_prev) in enumerate(zip(preds, and_not_preds[:-1])):
with ops.name_scope("case_%d" % i):
case_preds.append(math_ops.logical_and(p, and_not_p_prev))
with ops.name_scope("case_none_are_true"):
case_preds.append(and_not_preds[-1])
# Create an empty tensor, or list, with the right type and shape
with ops.name_scope("case_create_empty"):
dummy_value = default()
def _correct_empty(v):
if isinstance(v, ops.Operation):
return no_op()
elif v.dtype == dtypes.string:
return array_ops.constant("")
else:
return array_ops.constant(v.dtype.as_numpy_dtype())
if isinstance(dummy_value, collections.Sequence):
dummy_type = type(dummy_value)
empty = lambda: dummy_type(_correct_empty(v) for v in dummy_value)
else:
empty = lambda: _correct_empty(dummy_value)
# case_sequence = [
# cond(~p3 & ~p2 & ~p1, default, empty),
# cond(p3 & ~p2 & ~p1, f3, lambda: case_sequence[0]),
# cond(p2 & ~p1, f2, lambda: case_sequence[1]),
# cond(p1, f1, lambda: case_sequence[2])
# ]
#
# And the return value will be case_sequence[-1]
def _build_case():
all_fns = [fn for fn in fns]
all_fns.append(default)
prev_case = None
for i, (cp, fn) in enumerate(list(zip(case_preds, all_fns))[::-1]):
prev_case = cond(
cp, fn,
empty if i == 0 else lambda: prev_case,
name="If_%d" % i)
return prev_case
# case_sequence = [cond(p3 & ..., f3, default),
# cond(p2 & ..., f2, lambda: case_sequence[0]),
# ...
# cond(p1 & True, f1, lambda: case_sequence[i-1])]
# and prev_case_seq will loop from case_sequence[0] to case_sequence[-1]
if exclusive:
# TODO(ebrevdo): Add Where() for DT_BOOL, replace with Size(Where(preds))
preds_c = array_ops.pack(preds, name="preds_c")
num_true_conditions = math_ops.reduce_sum(
math_ops.cast(preds_c, dtypes.int32), name="num_true_conds")
@ -2022,21 +2057,11 @@ def case(pred_fn_pairs, default, exclusive=False, name="case"):
with ops.control_dependencies([
logging_ops.Assert(condition=at_most_one_true_condition,
data=error_msg, summarize=len(preds))]):
prev_case_seq = None
for i, (cp, fn) in enumerate(list(zip(case_preds, fns))[::-1]):
prev_case_seq = cond(
cp, fn,
default if i == 0 else lambda: prev_case_seq,
name="If_%d" % i)
case_seq = _build_case()
else:
prev_case_seq = None
for i, (cp, fn) in enumerate(list(zip(case_preds, fns))[::-1]):
prev_case_seq = cond(
cp, fn,
default if i == 0 else lambda: prev_case_seq,
name="If_%d" % i)
case_seq = _build_case()
return prev_case_seq
return case_seq
ops.RegisterShape("Enter")(common_shapes.unchanged_shape)

View File

@ -261,7 +261,7 @@ def merge_all_summaries(key=ops.GraphKeys.SUMMARIES):
Returns:
If no summaries were collected, returns None. Otherwise returns a scalar
`Tensor` of type`string` containing the serialized `Summary` protocol
`Tensor` of type `string` containing the serialized `Summary` protocol
buffer resulting from the merging.
"""
summary_ops = ops.get_collection(key)
@ -271,6 +271,30 @@ def merge_all_summaries(key=ops.GraphKeys.SUMMARIES):
return merge_summary(summary_ops)
def get_summary_op():
"""Returns a single Summary op that would run all summaries.
Either existing one from `SUMMARY_OP` collection or merges all existing
summaries.
Returns:
If no summaries were collected, returns None. Otherwise returns a scalar
`Tensor` of type `string` containing the serialized `Summary` protocol
buffer resulting from the merging.
"""
summary_op = ops.get_collection(ops.GraphKeys.SUMMARY_OP)
if summary_op is not None:
if summary_op:
summary_op = summary_op[0]
else:
summary_op = None
if summary_op is None:
summary_op = merge_all_summaries()
if summary_op is not None:
ops.add_to_collection(ops.GraphKeys.SUMMARY_OP, summary_op)
return summary_op
def scalar_summary(tags, values, collections=None, name=None):
"""Outputs a `Summary` protocol buffer with scalar values.

View File

@ -587,13 +587,16 @@ def separable_conv2d(input, depthwise_filter, pointwise_filter, strides,
padding="VALID", name=name)
def sufficient_statistics(x, axes, shift=True, keep_dims=False, name=None):
def sufficient_statistics(x, axes, shift=False, keep_dims=False, name=None):
"""Calculate the sufficient statistics for the mean and variance of `x`.
These sufficient statistics are computed using the one pass algorithm on
an input that's optionally shifted using the value of the 1st element in `x`.
See:
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Computing_shifted_data
Unfortunately, in some cases using a random individual sample as the shift
value leads experimentally to very poor numerical stability, so it is disabled
by default. The one-pass approach might have to be revised accordingly.
Args:
x: A `Tensor`.

View File

@ -752,6 +752,41 @@ def _calc_conv_weight_params(graph, node):
filter_in_depth * filter_out_depth))
@ops.RegisterStatistics("DepthwiseConv2dNative", "flops")
def _calc_depthwise_conv_flops(graph, node):
"""Calculates the compute resources needed for DepthwiseConv2dNative."""
input_shape = graph_util.tensor_shape_from_node_def_name(graph, node.input[0])
input_shape.assert_is_fully_defined()
filter_shape = graph_util.tensor_shape_from_node_def_name(graph,
node.input[1])
filter_shape.assert_is_fully_defined()
output_shape = graph_util.tensor_shape_from_node_def_name(graph, node.name)
output_shape.assert_is_fully_defined()
filter_height = int(filter_shape[0])
filter_width = int(filter_shape[1])
output_count = np.prod(output_shape.as_list())
return ops.OpStats("flops", (output_count * filter_height * filter_width * 2))
@ops.RegisterStatistics("DepthwiseConv2dNative", "weight_parameters")
def _calc_depthwise_conv_weight_params(graph, node):
"""Calculates the on-disk size of the weights for DepthwiseConv2dNative."""
input_shape = graph_util.tensor_shape_from_node_def_name(graph, node.input[0])
input_shape.assert_is_fully_defined()
filter_shape = graph_util.tensor_shape_from_node_def_name(graph,
node.input[1])
filter_shape.assert_is_fully_defined()
output_shape = graph_util.tensor_shape_from_node_def_name(graph, node.name)
output_shape.assert_is_fully_defined()
filter_height = int(filter_shape[0])
filter_width = int(filter_shape[1])
filter_in_depth = int(filter_shape[2])
filter_channel_multiplier = int(filter_shape[3])
return ops.OpStats("weight_parameters", (filter_height * filter_width *
filter_in_depth *
filter_channel_multiplier))
@ops.RegisterShape("Conv3D")
def _Conv3DShape(op):
"""Shape function for Conv3D."""

View File

@ -57,9 +57,9 @@ def add_check_numerics_ops():
"""
check_op = []
# This code relies on the ordering of ops in get_operations().
# The consumer of a tensor always comes before that tensor's producer in
# The producer of a tensor always comes before that tensor's consumer in
# this list. This is true because get_operations() returns ops in the order
# added, and ops can only be added once its inputs are added.
# added, and an op can only be added after its inputs are added.
for op in ops.get_default_graph().get_operations():
for output in op.outputs:
if output.dtype in [dtypes.float16, dtypes.float32, dtypes.float64]:

View File

@ -29,7 +29,7 @@ from tensorflow.python.platform import tf_logging as logging
__all__ = ["make_template"]
def make_template(name_, func_, **kwargs):
def make_template(name_, func_, create_scope_now_=False, **kwargs):
"""Given an arbitrary function, wrap it so that it does variable sharing.
This wraps `func_` in a Template and partially evaluates it. Templates are
@ -98,29 +98,39 @@ def make_template(name_, func_, **kwargs):
w2 = scale_by_y2(input2)
```
Note: The full variable scope is captured at the time of the first call.
Depending on the value of `create_scope_now_`, the full variable scope may be
captured either at the time of first call or at the time of construction. If
this option is set to True, then all Tensors created by repeated calls to the
template will have an extra trailing _N+1 to their name, as the first time the
scope is entered in the Template constructor no Tensors are created.
Note: `name_` and `func_` have a following underscore to reduce the likelihood
of collisions with kwargs.
Note: `name_`, `func_` and `create_scope_now_` have a trailing underscore to
reduce the likelihood of collisions with kwargs.
Args:
name_: A name for the scope created by this template. If necessary, the name
will be made unique by appending `_N` to the name.
func_: The function to wrap.
create_scope_now_: Boolean controlling whether the scope should be created
when the template is constructed or when the template is called. Default
is False, meaning the scope is created when the template is called.
**kwargs: Keyword arguments to apply to `func_`.
Returns:
A function that will enter a `variable_scope` before calling `func_`. The
first time it is called, it will create a non-reusing scope so that the
variables will be unique. On each subsequent call, it will reuse those
variables.
A function to encapsulate a set of variables which should be created once
and reused. An enclosing scope will created, either where `make_template`
is called, or wherever the result is called, depending on the value of
`create_scope_now_`. Regardless of the value, the first time the template
is called it will enter the scope with no reuse, and call `func_` to create
variables, which are guaranteed to be unique. All subsequent calls will
re-enter the scope and reuse those variables.
Raises:
ValueError: if the name is None.
"""
if kwargs:
func_ = functools.partial(func_, **kwargs)
return Template(name_, func_)
return Template(name_, func_, create_scope_now=create_scope_now_)
def _skip_common_stack_elements(stacktrace, base_case):
@ -137,10 +147,13 @@ class Template(object):
Templates are functions that create variables the first time they are called
and reuse them thereafter. See `make_template` for full documentation.
Note: The full variable scope is captured at the time of the first call.
Note: By default, the full variable scope is captured at the time of first
call. If `create_scope_now_` is passed as True to the constructor, the full
scope will be captured there, but no variables will created until the first
call.
"""
def __init__(self, name, func):
def __init__(self, name, func, create_scope_now=False):
"""Creates a template for the given function.
Args:
@ -148,6 +161,15 @@ class Template(object):
name will be made unique by appending `_N` to the it (see how
`tf.variable_op_scope` treats the `default_name` for details).
func: The function to apply each time.
create_scope_now: Whether to create the scope at Template construction
time, rather than first call. Defaults to false. Creating the scope at
construction time may be more convenient if the template is to passed
through much lower level code, and you want to be sure of the scope
name without knowing exactly where it will be first called. If set to
True, the scope will be created in the constructor, and all subsequent
times in __call__, leading to a trailing numeral being added to the
names of all created Tensors. If set to False, the scope will be created
at the first call location.
Raises:
ValueError: if the name is None.
@ -157,7 +179,14 @@ class Template(object):
self._name = name
if name is None:
raise ValueError("name cannot be None.")
self._var_scope = None
if create_scope_now:
with variable_scope.variable_op_scope([], None, self._name) as vs:
self._var_scope = vs
else:
self._var_scope = None
# This variable keeps track of whether the template has been called yet,
# which is not the same as whether the scope has been created.
self._variables_created = False
def _call_func(self, args, kwargs, check_for_new_variables):
try:
@ -204,12 +233,23 @@ class Template(object):
raise
def __call__(self, *args, **kwargs):
# Capture the name of the variable_scope here because if we capture at
# construction, then name_scopes would have a '_N+1' suffix.
if self._var_scope:
with variable_scope.variable_scope(self._var_scope, reuse=True):
return self._call_func(args, kwargs, check_for_new_variables=True)
if self._variables_created:
# This is not the first visit to __call__, so variables have already
# been created, and we want to reuse them.
with variable_scope.variable_scope(self._var_scope, reuse=True):
return self._call_func(args, kwargs, check_for_new_variables=True)
else:
# This is the first visit to __call__, but the scope has already been
# created in the constructor. Set _variables_created so that subsequent
# calls take the if branch above.
self._variables_created = True
with variable_scope.variable_scope(self._var_scope):
return self._call_func(args, kwargs, check_for_new_variables=False)
else:
# The scope was not created at construction time, so create it here.
# Subsequent calls should reuse variables.
self._variables_created = True
with variable_scope.variable_op_scope([], None, self._name) as vs:
self._var_scope = vs
return self._call_func(args, kwargs, check_for_new_variables=False)

Some files were not shown because too many files have changed in this diff Show More