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/ctc:all_files",
"//tensorflow/contrib/distributions:all_files", "//tensorflow/contrib/distributions:all_files",
"//tensorflow/contrib/ffmpeg: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/framework:all_files",
"//tensorflow/contrib/layers:all_files", "//tensorflow/contrib/layers:all_files",
"//tensorflow/contrib/layers/kernels: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.assertEqual(exponential.entropy().get_shape(), (3,))
self.assertAllClose(exponential.entropy().eval(), expected_entropy) 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__': if __name__ == '__main__':
tf.test.main() tf.test.main()

View File

@ -200,15 +200,26 @@ class ContinuousDistribution(BaseDistribution):
"""Base class for continuous probability distributions. """Base class for continuous probability distributions.
`ContinuousDistribution` defines the API for the likelihood functions `pdf` `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 ```Normal(mu, sigma) = sigma * Normal(0, 1) + mu```
class's implementation.
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 See `BaseDistribution` for more information on the API for probability
distributions. distributions.
""" """
@abc.abstractproperty
def is_reparameterized(self):
pass
@abc.abstractmethod @abc.abstractmethod
def pdf(self, value, name="pdf"): def pdf(self, value, name="pdf"):
"""Probability density function.""" """Probability density function."""

View File

@ -20,7 +20,11 @@ from __future__ import print_function
from tensorflow.contrib.distributions.python.ops import gamma from tensorflow.contrib.distributions.python.ops import gamma
from tensorflow.python.framework import ops 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 math_ops
from tensorflow.python.ops import random_ops
class Exponential(gamma.Gamma): class Exponential(gamma.Gamma):
@ -45,3 +49,35 @@ class Exponential(gamma.Gamma):
@property @property
def lam(self): def lam(self):
return self._lam 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 beta = self._beta
return (alpha - math_ops.log(beta) + math_ops.lgamma(alpha) + return (alpha - math_ops.log(beta) + math_ops.lgamma(alpha) +
(1 - alpha) * math_ops.digamma(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) sampled.set_shape(final_shape)
return sampled * self._sigma + self._mu 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) samples.set_shape(final_shape)
return samples return samples
@property
def is_reparameterized(self):
return True

View File

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

View File

@ -231,6 +231,10 @@ class Uniform(ContinuousDistribution):
"""`b - a`.""" """`b - a`."""
return self.b - self.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 # TODO(rsepassi): Find a more efficient way of doing the broadcasting in_ones
# and _zeros. # and _zeros.
def _ones(self): def _ones(self):

View File

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

View File

@ -18,7 +18,7 @@
#include <cstdio> #include <cstdio>
#include <set> #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.h"
#include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/lib/io/path.h" #include "tensorflow/core/lib/io/path.h"

View File

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

View File

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

View File

@ -13,8 +13,8 @@
// limitations under the License. // limitations under the License.
// ============================================================================= // =============================================================================
#ifndef 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_KERNELS_FFMPEG_LIB_H_ #define THIRD_PARTY_TENSORFLOW_CONTRIB_FFMPEG_DEFAULT_FFMPEG_LIB_H_
#include <string> #include <string>
@ -47,4 +47,4 @@ Status CreateAudioFile(const string& audio_format_id, int32 samples_per_second,
} // namespace ffmpeg } // namespace ffmpeg
} // namespace tensorflow } // 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. // limitations under the License.
// ============================================================================= // =============================================================================
#include "tensorflow/contrib/ffmpeg/kernels/ffmpeg_lib.h" #include "tensorflow/contrib/ffmpeg/default/ffmpeg_lib.h"
#include <stdlib.h> #include <stdlib.h>
#include <vector> #include <vector>
@ -35,7 +35,7 @@ namespace {
const char kTestWavFilename[] = const char kTestWavFilename[] =
"contrib/ffmpeg/testdata/mono_10khz.wav"; "contrib/ffmpeg/testdata/mono_10khz.wav";
const char kTestMp3Filename[] = 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 // Set to true via a command line flag iff the test is expected to have FFmpeg
// installed. // installed.

View File

@ -15,7 +15,7 @@
#include <limits> #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.h"
#include "tensorflow/core/framework/op_kernel.h" #include "tensorflow/core/framework/op_kernel.h"

View File

@ -117,8 +117,9 @@ def summarize_tensor(tensor, tag=None):
Returns: Returns:
The summary op created or None for string tensors. The summary op created or None for string tensors.
""" """
# Skips string tensors. # Skips string tensors and boolean tensors (not handled by the summaries).
if tensor.dtype.is_compatible_with(dtypes.string): if (tensor.dtype.is_compatible_with(dtypes.string) or
tensor.dtype.base_dtype == dtypes.bool):
return None return None
if tensor.get_shape().ndims == 0: 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( py_test(
name = "test_early_stopping", name = "test_early_stopping",
size = "medium", 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( py_test(
name = "test_grid_search", name = "test_grid_search",
size = "small", size = "small",

View File

@ -20,6 +20,9 @@ from __future__ import print_function
import numpy as np import numpy as np
from tensorflow.contrib.learn.python.learn import datasets 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 models
from tensorflow.contrib.learn.python.learn import monitors from tensorflow.contrib.learn.python.learn import monitors
from tensorflow.contrib.learn.python.learn import ops 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.autoencoder import TensorFlowDNNAutoencoder
from tensorflow.contrib.learn.python.learn.estimators.base import TensorFlowEstimator, TensorFlowBaseTransformer 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 TensorFlowDNNClassifier
from tensorflow.contrib.learn.python.learn.estimators.dnn import TensorFlowDNNRegressor 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 BaseEstimator
from tensorflow.contrib.learn.python.learn.estimators.estimator import Estimator 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.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 TensorFlowClassifier
from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowLinearClassifier from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowLinearClassifier
from tensorflow.contrib.learn.python.learn.estimators.linear import TensorFlowLinearRegressor 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.python.training import training as train
from tensorflow.contrib.layers import optimizers 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_train_data_feeder
from tensorflow.contrib.learn.python.learn.io.data_feeder import setup_predict_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.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 import _sklearn
from tensorflow.contrib.learn.python.learn.estimators._sklearn import NotFittedError from tensorflow.contrib.learn.python.learn.estimators._sklearn import NotFittedError
from tensorflow.contrib.learn.python.learn.estimators.run_config import RunConfig from tensorflow.contrib.learn.python.learn.estimators.run_config import RunConfig
@ -63,7 +64,35 @@ def _write_with_backup(filename, content):
f.write(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. """Base class for all TensorFlow estimators.
Parameters: Parameters:
@ -109,101 +138,21 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
continue_training=False, continue_training=False,
config=None, config=None,
verbose=1): 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.n_classes = n_classes
self.batch_size = batch_size self.batch_size = batch_size
self.steps = steps self.steps = steps
self.verbose = verbose self.verbose = verbose
self.optimizer = optimizer
self.learning_rate = learning_rate
self.clip_gradients = clip_gradients
self.continue_training = continue_training self.continue_training = continue_training
self._initialized = False self._data_feeder = None
self.class_weight = class_weight
self._config = config
def _setup_training(self): def fit(self, x, y, steps=None, monitors=None, logdir=None):
"""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):
"""Builds a neural network model given provided `model_fn` and training """Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -214,63 +163,44 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
To restart learning, create new estimator. To restart learning, create new estimator.
Args: 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 iterator that returns arrays of features. The training input
samples for fitting the model. samples for fitting the model.
y: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be y: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be
iterator that returns array of targets. The training target values iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
monitor: Monitor object to print training progress and invoke early steps: int, number of steps to train.
stopping 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 logdir: the directory to save the log file that can be used for
optional visualization. optional visualization.
Returns: Returns:
Returns self. Returns self.
""" """
# Sets up data feeder. if logdir is not None:
self._data_feeder = setup_train_data_feeder(X, y, self.n_classes, self._model_dir = logdir
self.batch_size) self._data_feeder = setup_train_data_feeder(
x, y, n_classes=self.n_classes, batch_size=self.batch_size)
if monitor is None: self._train_model(input_fn=self._data_feeder.input_builder,
self._monitor = monitors.default_monitor(verbose=self.verbose) feed_fn=self._data_feeder.get_feed_dict_fn(),
else: steps=steps or self.steps,
self._monitor = monitor monitors=monitors)
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)
return self 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. """Incremental fit on a batch of samples.
This method is expected to be called several times consecutively 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. to converge, and you want to split up training into subparts.
Args: 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 iterator that returns arrays of features. The training input
samples for fitting the model. samples for fitting the model.
y: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be y: vector or matrix [n_samples] or [n_samples, n_outputs]. Can be
@ -292,33 +222,30 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Returns: Returns:
Returns self. Returns self.
""" """
return self.fit(X, y) return self.fit(x, y)
def _predict(self, X, axis=-1, batch_size=None):
if not self._initialized:
raise _sklearn.NotFittedError()
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. # Use the batch size for fitting if the user did not specify one.
if batch_size is None: if batch_size is None:
batch_size = self.batch_size batch_size = self.batch_size
self._graph.add_to_collection('IS_TRAINING', False) predict_data_feeder = setup_train_data_feeder(
predict_data_feeder = setup_predict_data_feeder(X, batch_size=batch_size) x, None, n_classes=None,
preds = [] batch_size=batch_size,
dropouts = self._graph.get_collection(DROPOUTS) shuffle=False, epochs=1)
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)
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. """Predict class or regression for X.
For a classification model, the predicted class for each sample in X is For a classification model, the predicted class for each sample in X is
@ -326,7 +253,7 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
returned. returned.
Args: 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. axis: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. Use 2 for sequence predictions.
@ -338,13 +265,13 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
y: array of shape [n_samples]. The predicted classes or predicted y: array of shape [n_samples]. The predicted classes or predicted
value. 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. """Predict class probability of the input samples X.
Args: 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 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. 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 y: array of shape [n_samples, n_classes]. The predicted
probabilities for each class. 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): def get_tensor(self, name):
"""Returns tensor by name. """Returns tensor by name.
@ -374,7 +301,9 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Returns: Returns:
Numpy array - value of the tensor. 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): def get_variable_names(self):
"""Returns list of all variable names in this model. """Returns list of all variable names in this model.
@ -382,8 +311,7 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Returns: Returns:
List of names. List of names.
""" """
with self._graph.as_default(): return [name for name, _ in checkpoints.list_variables(self.model_dir)]
return [v.name for v in variables.all_variables()]
def save(self, path): def save(self, path):
"""Saves checkpoints and graph to given path. """Saves checkpoints and graph to given path.
@ -391,17 +319,12 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Args: Args:
path: Folder to save model to. path: Folder to save model to.
""" """
if not self._initialized: if self._graph is None:
raise _sklearn.NotFittedError() raise NotFittedError
# Currently Saver requires absolute path to work correctly. # Copy model dir into new path.
path = os.path.abspath(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. # Save model definition.
all_params = self.get_params() all_params = self.get_params()
params = {} params = {}
@ -414,25 +337,6 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
default=lambda o: o.__dict__ if hasattr(o, '__dict__') else None) default=lambda o: o.__dict__ if hasattr(o, '__dict__') else None)
_write_with_backup(os.path.join(path, 'model.def'), model_def) _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): def _restore(self, path):
"""Restores this estimator from given path. """Restores this estimator from given path.
@ -442,57 +346,7 @@ class TensorFlowEstimator(_sklearn.BaseEstimator):
Args: Args:
path: Path to checkpoints and other information. path: Path to checkpoints and other information.
""" """
# Currently Saver requires absolute path to work correctly. raise NotImplementedError
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
# pylint: disable=unused-argument # pylint: disable=unused-argument
@classmethod @classmethod
@ -549,7 +403,7 @@ class TensorFlowBaseTransformer(TensorFlowEstimator, _sklearn.TransformerMixin):
def fit(self, X, y=None, monitor=None, logdir=None): def fit(self, X, y=None, monitor=None, logdir=None):
"""Fit a transformer.""" """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): def fit_transform(self, X, y=None, monitor=None, logdir=None):
"""Fit transformer and transform X using trained transformer.""" """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 division
from __future__ import print_function from __future__ import print_function
from tensorflow.contrib.learn.python.learn.estimators import _sklearn from tensorflow.contrib import layers
from tensorflow.contrib.learn.python.learn.estimators.base import TensorFlowEstimator
from tensorflow.contrib.learn.python.learn import models 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): class TensorFlowDNNClassifier(TensorFlowEstimator, _sklearn.ClassifierMixin):
"""TensorFlow DNN Classifier model. """TensorFlow DNN Classifier model.
@ -84,16 +249,16 @@ class TensorFlowDNNClassifier(TensorFlowEstimator, _sklearn.ClassifierMixin):
@property @property
def weights_(self): def weights_(self):
"""Returns weights of the DNN weight layers.""" """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') 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 @property
def bias_(self): def bias_(self):
"""Returns bias of the DNN's bias layers.""" """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') 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): class TensorFlowDNNRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@ -157,13 +322,13 @@ class TensorFlowDNNRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@property @property
def weights_(self): def weights_(self):
"""Returns weights of the DNN weight layers.""" """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') 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 @property
def bias_(self): def bias_(self):
"""Returns bias of the DNN's bias layers.""" """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') 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 os
import tempfile import tempfile
import time import time
import types
import numpy as np
import six import six
from tensorflow.contrib import framework as contrib_framework from tensorflow.contrib import framework as contrib_framework
from tensorflow.contrib import layers from tensorflow.contrib import layers
from tensorflow.contrib import losses 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 _sklearn as sklearn
from tensorflow.contrib.learn.python.learn.estimators import run_config from tensorflow.contrib.learn.python.learn.estimators import run_config
from tensorflow.contrib.learn.python.learn.estimators import tensor_signature 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 ops
from tensorflow.python.framework import random_seed 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.platform import tf_logging as logging
from tensorflow.python.training import device_setter from tensorflow.python.training import device_setter
from tensorflow.python.training import saver 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, df = data_feeder.setup_train_data_feeder(x, None,
n_classes=None, n_classes=None,
batch_size=batch_size) batch_size=batch_size, epochs=1)
return df.input_builder, df.get_feed_dict_fn() 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 # TODO(wicke): Remove this once launcher takes over config functionality
_Config = run_config.RunConfig # pylint: disable=invalid-name _Config = run_config.RunConfig # pylint: disable=invalid-name
def __init__(self, model_dir=None): def __init__(self, model_dir=None, config=None):
# Model directory. # Model directory.
self._model_dir = model_dir self._model_dir = model_dir
if self._model_dir is None: if self._model_dir is None:
@ -121,7 +127,10 @@ class BaseEstimator(sklearn.BaseEstimator):
self._model_dir) self._model_dir)
# Create a run configuration # 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. # Set device function depending if there are replicas or not.
if self._config.num_ps_replicas > 0: if self._config.num_ps_replicas > 0:
@ -136,6 +145,12 @@ class BaseEstimator(sklearn.BaseEstimator):
self._features_info = None self._features_info = None
self._targets_info = None self._targets_info = None
self._graph = None
@property
def model_dir(self):
return self._model_dir
@abc.abstractproperty @abc.abstractproperty
def _get_train_ops(self, features, targets): def _get_train_ops(self, features, targets):
"""Method that builds model graph and returns trainer ops. """Method that builds model graph and returns trainer ops.
@ -204,7 +219,7 @@ class BaseEstimator(sklearn.BaseEstimator):
""" """
return {} 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. """Trains a model given training data X and y.
Args: Args:
@ -216,8 +231,8 @@ class BaseEstimator(sklearn.BaseEstimator):
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
steps: number of steps to train model for. steps: number of steps to train model for.
batch_size: minibatch size to use on the input, defaults to 32. batch_size: minibatch size to use on the input, defaults to 32.
monitor: monitor object to print training progress and invoke monitors: List of `BaseMonitor` subclass instances. Used for callbacks
early stopping. inside the training loop.
Returns: Returns:
Returns self. Returns self.
@ -226,24 +241,24 @@ class BaseEstimator(sklearn.BaseEstimator):
return self._train_model(input_fn=input_fn, return self._train_model(input_fn=input_fn,
feed_fn=feed_fn, feed_fn=feed_fn,
steps=steps, 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. """Trains a model given input builder function.
Args: Args:
input_fn: Input builder function, returns tuple of dicts or input_fn: Input builder function, returns tuple of dicts or
dict and Tensor. dict and Tensor.
steps: number of steps to train model for. steps: number of steps to train model for.
monitor: monitor object to print training progress and invoke monitors: List of `BaseMonitor` subclass instances. Used for callbacks
early stopping. inside the training loop.
Returns: Returns:
Returns self. 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. """Incremental fit on a batch of samples.
This method is expected to be called several times consecutively 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). (class label in classification, real numbers in regression).
steps: number of steps to train model for. steps: number of steps to train model for.
batch_size: minibatch size to use on the input, defaults to 32. batch_size: minibatch size to use on the input, defaults to 32.
monitor: Monitor object to print training progress and invoke monitors: List of `BaseMonitor` subclass instances. Used for callbacks
early stopping. inside the training loop.
Returns: Returns:
Returns self. Returns self.
@ -273,7 +288,7 @@ class BaseEstimator(sklearn.BaseEstimator):
return self._train_model(input_fn=input_fn, return self._train_model(input_fn=input_fn,
feed_fn=feed_fn, feed_fn=feed_fn,
steps=steps, steps=steps,
monitor=monitor) monitors=monitors)
def evaluate(self, x=None, y=None, input_fn=None, feed_fn=None, def evaluate(self, x=None, y=None, input_fn=None, feed_fn=None,
batch_size=32, steps=100, metrics=None): batch_size=32, steps=100, metrics=None):
@ -323,7 +338,7 @@ class BaseEstimator(sklearn.BaseEstimator):
Args: Args:
x: features. x: features.
batch_size: OVerride default batch size. batch_size: Override default batch size.
Returns: Returns:
Numpy array of predicted probabilities. Numpy array of predicted probabilities.
@ -338,20 +353,24 @@ class BaseEstimator(sklearn.BaseEstimator):
(str(features), str(self._features_info))) (str(features), str(self._features_info)))
else: else:
self._features_info = tensor_signature.create_signatures(features) self._features_info = tensor_signature.create_signatures(features)
if self._targets_info is not None: if targets is not None:
if not tensor_signature.tensors_compatible(targets, self._targets_info): if self._targets_info is not None:
raise ValueError('Targets are incompatible with given information. ' if not tensor_signature.tensors_compatible(targets, self._targets_info):
'Given targets: %s, required signatures: %s.' % raise ValueError('Targets are incompatible with given information. '
(str(targets), str(self._targets_info))) 'Given targets: %s, required signatures: %s.' %
else: (str(targets), str(self._targets_info)))
self._targets_info = tensor_signature.create_signatures(targets) else:
self._targets_info = tensor_signature.create_signatures(targets)
def _train_model(self, def _train_model(self,
input_fn, input_fn,
steps, steps,
feed_fn=None, feed_fn=None,
init_op=None,
init_feed_fn=None,
init_fn=None,
device_fn=None, device_fn=None,
monitor=None, monitors=None,
log_every_steps=100, log_every_steps=100,
fail_on_nan_loss=True): fail_on_nan_loss=True):
if self._config.execution_mode not in ('all', 'train'): if self._config.execution_mode not in ('all', 'train'):
@ -369,24 +388,42 @@ class BaseEstimator(sklearn.BaseEstimator):
# Device allocation # Device allocation
device_fn = device_fn or self._device_fn 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) random_seed.set_random_seed(self._config.tf_random_seed)
global_step = contrib_framework.create_global_step(g) global_step = contrib_framework.create_global_step(g)
features, targets = input_fn() features, targets = input_fn()
self._check_inputs(features, targets) self._check_inputs(features, targets)
train_op, loss_op = self._get_train_ops(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( return train(
graph=g, graph=g,
output_dir=self._model_dir, output_dir=self._model_dir,
train_op=train_op, train_op=train_op,
loss_op=loss_op, loss_op=loss_op,
global_step_tensor=global_step, 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, log_every_steps=log_every_steps,
supervisor_is_chief=(self._config.task == 0), supervisor_is_chief=(self._config.task == 0),
supervisor_master=self._config.master, supervisor_master=self._config.master,
feed_fn=feed_fn, feed_fn=feed_fn,
max_steps=steps, 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): def _evaluate_model(self, input_fn, steps, feed_fn=None, metrics=None):
if self._config.execution_mode not in ('all', 'evaluate', 'eval_evalset'): if self._config.execution_mode not in ('all', 'evaluate', 'eval_evalset'):
@ -413,22 +450,41 @@ class BaseEstimator(sklearn.BaseEstimator):
max_steps=steps) max_steps=steps)
return eval_results 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. # Converts inputs into tf.DataFrame / tf.Series.
batch_size = -1 if batch_size is None else batch_size 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) checkpoint_path = saver.latest_checkpoint(self._model_dir)
with ops.Graph().as_default() as g: with ops.Graph().as_default() as g:
random_seed.set_random_seed(self._config.tf_random_seed) random_seed.set_random_seed(self._config.tf_random_seed)
contrib_framework.create_global_step(g) contrib_framework.create_global_step(g)
features, _ = input_fn() features, _ = input_fn()
feed_dict = feed_fn() if feed_fn is not None else None
predictions = self._get_predict_ops(features) predictions = self._get_predict_ops(features)
if not isinstance(predictions, dict): if not isinstance(predictions, dict):
predictions = {'predictions': predictions} predictions = {'predictions': predictions}
# TODO(ipolosukhin): Support batching # 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): class Estimator(BaseEstimator):
@ -449,16 +505,18 @@ class Estimator(BaseEstimator):
(like tf.train.GradientDescentOptimizer). (like tf.train.GradientDescentOptimizer).
clip_gradients: clip_norm value for call to `clip_by_global_norm`. None clip_gradients: clip_norm value for call to `clip_by_global_norm`. None
denotes no gradient clipping. denotes no gradient clipping.
config: Configuration object.
""" """
def __init__(self, def __init__(self,
model_fn=None, model_fn=None,
model_dir=None, model_dir=None,
classification=True, classification=True,
learning_rate=0.01, learning_rate=0.1,
optimizer='SGD', optimizer='Adagrad',
clip_gradients=None): clip_gradients=None,
super(Estimator, self).__init__(model_dir=model_dir) config=None):
super(Estimator, self).__init__(model_dir=model_dir, config=config)
self._model_fn = model_fn self._model_fn = model_fn
self._classification = classification self._classification = classification
@ -486,12 +544,25 @@ class Estimator(BaseEstimator):
Tuple of train `Operation` and loss `Tensor`. Tuple of train `Operation` and loss `Tensor`.
""" """
_, loss = self._model_fn(features, targets, ModeKeys.TRAIN) _, 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( train_op = layers.optimize_loss(
loss, loss,
contrib_framework.get_global_step(), contrib_framework.get_global_step(),
learning_rate=self.learning_rate, learning_rate=learning_rate,
optimizer=self.optimizer, optimizer=optimizer,
clip_gradients=self.clip_gradients) 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 return train_op, loss
def _get_eval_ops(self, features, targets, metrics): 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) 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): class EstimatorTest(tf.test.TestCase):
def testTrain(self): def testTrain(self):
@ -64,6 +82,12 @@ class EstimatorTest(tf.test.TestCase):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
est.train(input_fn=other_input_fn, steps=1) 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__': if __name__ == '__main__':
tf.test.main() tf.test.main()

View File

@ -16,11 +16,151 @@ from __future__ import absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
from tensorflow.contrib.learn.python.learn.estimators import _sklearn from tensorflow.contrib import layers
from tensorflow.contrib.learn.python.learn.estimators.base import TensorFlowEstimator
from tensorflow.contrib.learn.python.learn import models 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): class TensorFlowLinearRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
"""TensorFlow Linear Regression model.""" """TensorFlow Linear Regression model."""
@ -50,12 +190,12 @@ class TensorFlowLinearRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@property @property
def weights_(self): def weights_(self):
"""Returns weights of the linear regression.""" """Returns weights of the linear regression."""
return self.get_tensor_value('linear_regression/weights:0') return self.get_tensor_value('linear_regression/weights')
@property @property
def bias_(self): def bias_(self):
"""Returns bias of the linear regression.""" """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): class TensorFlowLinearClassifier(TensorFlowEstimator, _sklearn.ClassifierMixin):
@ -89,12 +229,12 @@ class TensorFlowLinearClassifier(TensorFlowEstimator, _sklearn.ClassifierMixin):
@property @property
def weights_(self): def weights_(self):
"""Returns weights of the linear classifier.""" """Returns weights of the linear classifier."""
return self.get_tensor_value('logistic_regression/weights:0') return self.get_tensor_value('logistic_regression/weights')
@property @property
def bias_(self): def bias_(self):
"""Returns weights of the linear classifier.""" """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 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 @property
def bias_(self): def bias_(self):
"""Returns bias of the rnn layer.""" """Returns bias of the rnn layer."""
return self.get_tensor_value('logistic_regression/bias:0') return self.get_tensor_value('logistic_regression/bias')
@property @property
def weights_(self): def weights_(self):
"""Returns weights of the rnn layer.""" """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): class TensorFlowRNNRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@ -201,9 +201,9 @@ class TensorFlowRNNRegressor(TensorFlowEstimator, _sklearn.RegressorMixin):
@property @property
def bias_(self): def bias_(self):
"""Returns bias of the rnn layer.""" """Returns bias of the rnn layer."""
return self.get_tensor_value('linear_regression/bias:0') return self.get_tensor_value('linear_regression/bias')
@property @property
def weights_(self): def weights_(self):
"""Returns weights of the rnn layer.""" """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 ops as contrib_ops
from tensorflow.contrib.framework.python.ops import variables as contrib_variables from tensorflow.contrib.framework.python.ops import variables as contrib_variables
from tensorflow.contrib.layers.python.layers import summaries 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.core.util.event_pb2 import SessionLog
from tensorflow.python.client import session as tf_session from tensorflow.python.client import session as tf_session
from tensorflow.python.framework import errors from tensorflow.python.framework import errors
from tensorflow.python.framework import ops from tensorflow.python.framework import ops
from tensorflow.python.framework import tensor_util from tensorflow.python.framework import tensor_util
from tensorflow.python.ops import data_flow_ops from tensorflow.python.ops import data_flow_ops
from tensorflow.python.ops import logging_ops
from tensorflow.python.ops import variables from tensorflow.python.ops import variables
from tensorflow.python.platform import gfile from tensorflow.python.platform import gfile
from tensorflow.python.platform import tf_logging as logging from tensorflow.python.platform import tf_logging as logging
@ -98,23 +100,24 @@ def _prepare_session(graph,
start_services, start_services,
global_step_tensor, global_step_tensor,
init_op=None, init_op=None,
init_feed_dict=None,
init_fn=None, init_fn=None,
supervisor_is_chief=True, supervisor_is_chief=True,
supervisor_master='', supervisor_master='',
supervisor_save_model_secs=600, supervisor_save_model_secs=600):
supervisor_save_summaries_secs=10):
"""Starts a session using the supervisor.""" """Starts a session using the supervisor."""
if global_step_tensor is None: if global_step_tensor is None:
global_step_tensor = Supervisor.USE_DEFAULT global_step_tensor = Supervisor.USE_DEFAULT
supervisor = Supervisor( supervisor = Supervisor(
graph, graph,
init_op=init_op or Supervisor.USE_DEFAULT, init_op=init_op or Supervisor.USE_DEFAULT,
init_feed_dict=init_feed_dict,
is_chief=supervisor_is_chief, is_chief=supervisor_is_chief,
logdir=output_dir, logdir=output_dir,
saver=_make_saver(graph), saver=_make_saver(graph),
global_step=global_step_tensor, global_step=global_step_tensor,
summary_op=None,
save_model_secs=supervisor_save_model_secs, save_model_secs=supervisor_save_model_secs,
save_summaries_secs=supervisor_save_summaries_secs,
init_fn=init_fn) init_fn=init_fn)
session = supervisor.PrepareSession(master=supervisor_master, session = supervisor.PrepareSession(master=supervisor_master,
start_standard_services=start_services) start_standard_services=start_services)
@ -122,6 +125,23 @@ def _prepare_session(graph,
return supervisor, session 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(ptucker): Add unit test.
# TODO(wicke): switch to forced named kwargs # TODO(wicke): switch to forced named kwargs
def train(graph, def train(graph,
@ -130,15 +150,17 @@ def train(graph,
loss_op, loss_op,
global_step_tensor=None, global_step_tensor=None,
init_op=None, init_op=None,
init_feed_dict=None,
init_fn=None, init_fn=None,
log_every_steps=10, log_every_steps=10,
supervisor_is_chief=True, supervisor_is_chief=True,
supervisor_master='', supervisor_master='',
supervisor_save_model_secs=600, supervisor_save_model_secs=600,
supervisor_save_summaries_secs=10, supervisor_save_summaries_steps=100,
feed_fn=None, feed_fn=None,
max_steps=None, max_steps=None,
fail_on_nan_loss=True): fail_on_nan_loss=True,
monitors=None):
"""Train a model. """Train a model.
Given `graph`, a directory to write outputs to (`output_dir`), and some ops, 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`. 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 init_op: An op that initializes the graph. If `None`, use `Supervisor`'s
default. 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. init_fn: Optional callable passed to Supervisor to initialize the model.
log_every_steps: Output logs regularly. The logs contain timing data and the log_every_steps: Output logs regularly. The logs contain timing data and the
current loss. current loss.
@ -172,13 +196,15 @@ def train(graph,
supervisor_master: The master string to use when preparing the session. supervisor_master: The master string to use when preparing the session.
supervisor_save_model_secs: Save a checkpoint every supervisor_save_model_secs: Save a checkpoint every
`supervisor_save_model_secs` seconds when training. `supervisor_save_model_secs` seconds when training.
supervisor_save_summaries_secs: Save summaries every supervisor_save_summaries_steps: Save summaries every
`supervisor_save_summaries_secs` seconds when training. `supervisor_save_summaries_steps` seconds when training.
feed_fn: A function that is called every iteration to produce a `feed_dict` feed_fn: A function that is called every iteration to produce a `feed_dict`
passed to `session.run` calls. Optional. passed to `session.run` calls. Optional.
max_steps: Train until `global_step_tensor` evaluates to this value. max_steps: Train until `global_step_tensor` evaluates to this value.
fail_on_nan_loss: If true, raise `NanLossDuringTrainingError` if `loss_op` fail_on_nan_loss: If true, raise `NanLossDuringTrainingError` if `loss_op`
evaluates to `NaN`. If false, continue training as if nothing happened. 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: Returns:
The final loss value. The final loss value.
@ -194,17 +220,30 @@ def train(graph,
graph, global_step_tensor) graph, global_step_tensor)
if global_step_tensor is None: if global_step_tensor is None:
raise ValueError('No "global_step" was provided or found in the graph.') 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( supervisor, session = _prepare_session(
graph=graph, graph=graph,
output_dir=output_dir, output_dir=output_dir,
start_services=True, start_services=True,
global_step_tensor=global_step_tensor, global_step_tensor=global_step_tensor,
init_op=init_op, init_op=init_op,
init_feed_dict=init_feed_dict,
init_fn=init_fn, init_fn=init_fn,
supervisor_is_chief=supervisor_is_chief, supervisor_is_chief=supervisor_is_chief,
supervisor_master=supervisor_master, supervisor_master=supervisor_master,
supervisor_save_model_secs=supervisor_save_model_secs, supervisor_save_model_secs=supervisor_save_model_secs)
supervisor_save_summaries_secs=supervisor_save_summaries_secs)
with session: with session:
get_current_step = lambda: session.run(global_step_tensor) get_current_step = lambda: session.run(global_step_tensor)
@ -215,13 +254,18 @@ def train(graph,
loss_value = None loss_value = None
logging.info('Training steps [%d,%s)', last_step, 'inf' logging.info('Training steps [%d,%s)', last_step, 'inf'
if max_steps is None else str(max_steps)) if max_steps is None else str(max_steps))
excinfo = None excinfo = None
try: try:
while not supervisor.ShouldStop() and ( while not supervisor.ShouldStop() and (
(max_steps is None) or (last_step < max_steps)): (max_steps is None) or (last_step < max_steps)):
start_time = time.time() start_time = time.time()
feed_dict = feed_fn() if feed_fn is not None else None 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): if np.isnan(loss_value):
failure_message = 'Model diverged with loss = NaN.' failure_message = 'Model diverged with loss = NaN.'
if fail_on_nan_loss: if fail_on_nan_loss:
@ -230,6 +274,9 @@ def train(graph,
else: else:
logging.warning(failure_message) logging.warning(failure_message)
if should_stop:
break
this_step = get_current_step() this_step = get_current_step()
if this_step <= last_step: if this_step <= last_step:
@ -268,12 +315,11 @@ def train(graph,
logging.info('Saving checkpoint for step %d to checkpoint: %s.' % ( logging.info('Saving checkpoint for step %d to checkpoint: %s.' % (
last_step, ckpt_path)) last_step, ckpt_path))
supervisor.saver.save(session, ckpt_path, global_step=last_step) supervisor.saver.save(session, ckpt_path, global_step=last_step)
if supervisor.summary_op is not None:
summary_strs = session.run(supervisor.summary_op) # Finish monitors.
supervisor.summary_writer.add_summary(summary_strs, last_step) for monitor in monitors:
supervisor.summary_writer.add_session_log( monitor.end()
SessionLog(status=SessionLog.STOP), last_step)
supervisor.summary_writer.close()
# catch OutOfRangeError which is thrown when queue is out of data (and for # catch OutOfRangeError which is thrown when queue is out of data (and for
# other reasons as well). # other reasons as well).
except errors.OutOfRangeError as e: except errors.OutOfRangeError as e:
@ -354,6 +400,9 @@ def evaluate(graph,
if isinstance(value, ops.Tensor): if isinstance(value, ops.Tensor):
summaries.summarize_tensor(value, tag=key) 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. # TODO(wicke): Don't use supervisor here, or switch to output_dir=eval_dir.
supervisor, session = _prepare_session( supervisor, session = _prepare_session(
graph=graph, graph=graph,
@ -363,8 +412,7 @@ def evaluate(graph,
init_op=init_op, init_op=init_op,
supervisor_is_chief=True, supervisor_is_chief=True,
supervisor_master=supervisor_master, supervisor_master=supervisor_master,
supervisor_save_model_secs=None, supervisor_save_model_secs=None)
supervisor_save_summaries_secs=None)
global_step_tensor = supervisor.global_step global_step_tensor = supervisor.global_step
with session: with session:
@ -394,14 +442,17 @@ def evaluate(graph,
', '.join('%s = %s' % (k, v) ', '.join('%s = %s' % (k, v)
for k, v in eval_results.items())) for k, v in eval_results.items()))
finally: finally:
# Make our own summary writer and write a summary to the eval dir # Make our own summary writer and write a summary to the eval dir.
if supervisor.summary_op is not None: # 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 summary_writer = None
try: try:
summary_writer = SummaryWriter(output_dir, summary_writer = SummaryWriter(output_dir,
graph_def=session.graph_def) graph_def=session.graph_def)
summary_str = session.run(supervisor.summary_op) summary_str = session.run(summary_op)
if summary_str: if summary_str:
summary_writer.add_summary(summary_str, current_global_step) summary_writer.add_summary(summary_str, current_global_step)
finally: finally:
@ -414,7 +465,10 @@ def evaluate(graph,
# catch OutOfRangeError which is thrown when queue is out of data (and for # catch OutOfRangeError which is thrown when queue is out of data (and for
# other reasons as well). # other reasons as well).
except errors.OutOfRangeError as e: 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 return eval_results, current_global_step

View File

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

View File

@ -17,221 +17,199 @@ from __future__ import absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
import os from tensorflow.python.platform import tf_logging as logging
import sys from tensorflow.python.training import summary_io
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)
class BaseMonitor(object): class BaseMonitor(object):
"""Base class for all learning monitors. """Base class for 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.
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): def set_estimator(self, estimator):
self._estimator = estimator self._estimator = estimator
def monitor_inducing_stop(self): def begin(self, max_steps=None):
"""Returns True if the monitor requests the model stop. """Callback at the beginning of training/evaluation.
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
Args: Args:
inp: not used max_steps: Maximum steps this training will run until.
out: not used
""" """
pass pass
def _set_epoch(self, feed_params_fn): def end(self):
"""Sets self.epoch from a function providing this info in a dict.""" """Callback at the end of training/evaluation."""
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
"""
pass pass
def epoch_begin(self, epoch):
pass
class ValidationMonitor(BaseMonitor): def epoch_end(self, epoch):
"""Monitor that reports validation score and uses it for early stopping. 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: Parameters:
val_X: Validation features every_n_steps: int, calls `every_n_step_{begin,end}` every this many steps.
val_y: Validation labels first_n_steps: int, calls `every_n_step_{begin,end}` for first n steps.
n_classes: Number of labels in output. 0 for regression
print_steps: Number of steps in between printing cost. TODO(ipolosukhin): Add also every n seconds.
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)
""" """
def __init__(self, def __init__(
val_X, self, every_n_steps=100, first_n_steps=1):
val_y, self._every_n_steps = every_n_steps
n_classes=0, self._first_n_steps = first_n_steps
print_steps=100, self._max_steps = None
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 create_val_feed_dict(self, inp, out): def begin(self, max_steps=None):
"""Set tensorflow placeholders and create validation data feed.""" self._max_steps = max_steps
self.val_feeder.set_placeholders(inp, out)
self.val_dict = self.val_feeder.get_feed_dict_fn()() 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): def set_estimator(self, estimator):
super(ValidationMonitor, self).set_estimator(estimator) super(SummarySaver, self).set_estimator(estimator)
if estimator._output_dir is None: self._summary_writer = summary_io.SummaryWriter(self._estimator.model_dir)
return
self._summary_writer = train.SummaryWriter(os.path.join(estimator._output_dir, 'eval'))
def _set_last_loss_seen(self): def every_n_step_begin(self, unused_step, tensors):
"""Sets self.last_loss_seen to most recent validation loss. return tensors + [self._summary_op]
Also stores this value to appropriate buffers def every_n_step_end(self, step, outputs):
""" summary_strs = outputs[self._summary_op.name]
[val_loss] = self.sess.run( if self._summary_writer:
[self.loss_expression_tensor], self._summary_writer.add_summary(summary_strs, step)
feed_dict=self.val_dict) return False
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 _modify_summary_string(self): def end(self):
"""Flushes validation print buffer into summary string.""" self._summary_writer.flush()
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( class ValidationMonitor(EveryN):
val_loss=avg_val_loss) """Runs evaluation every n steps.
self._summary_str = (", ".join([self._summary_str, val_loss_string]))
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 __future__ import print_function
from tensorflow.contrib import layers 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 nn
from tensorflow.python.ops import variable_scope as vs 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): 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: if activation is not None:
tensor_in = activation(tensor_in) tensor_in = activation(tensor_in)
if dropout is not None: 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 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 absolute_import
from __future__ import division from __future__ import division
from __future__ import print_function from __future__ import print_function
from __future__ import unicode_literals
import random import random
@ -61,13 +60,14 @@ class BaseTest(tf.test.TestCase):
classifier.fit(iris.data, [float(x) for x in iris.target]) classifier.fit(iris.data, [float(x) for x in iris.target])
self.assertEqual( self.assertEqual(
classifier.get_variable_names(), classifier.get_variable_names(),
["global_step:0", "logistic_regression/weights:0", ["OptimizeLoss/learning_rate",
"logistic_regression/bias:0", "OptimizeLoss/logistic_regression/bias/Adagrad",
"OptimizeLoss/logistic_regression/softmax_classifier/" "OptimizeLoss/logistic_regression/softmax_classifier/"
"softmax_cross_entropy_loss/value/avg:0", "softmax_cross_entropy_loss/value/avg",
"OptimizeLoss/learning_rate:0", "OptimizeLoss/logistic_regression/weights/Adagrad",
"OptimizeLoss/logistic_regression/weights/Adagrad:0", "global_step",
"OptimizeLoss/logistic_regression/bias/Adagrad:0"]) "logistic_regression/bias",
"logistic_regression/weights"])
def testIrisSummaries(self): def testIrisSummaries(self):
iris = datasets.load_iris() iris = datasets.load_iris()
@ -84,9 +84,11 @@ class BaseTest(tf.test.TestCase):
steps=250) steps=250)
classifier.fit(iris.data, iris.target) classifier.fit(iris.data, iris.target)
score1 = accuracy_score(iris.target, classifier.predict(iris.data)) 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)) 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): def testIrisStreaming(self):
iris = datasets.load_iris() 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, X_val, y_train, y_val = train_test_split(
X_train, y_train, test_size=0.2) 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 # classifier without early stopping - overfitting
classifier1 = learn.TensorFlowDNNClassifier(hidden_units=[10, 20, 10], classifier1 = learn.TensorFlowDNNClassifier(hidden_units=[10, 20, 10],
@ -52,7 +53,7 @@ class EarlyStoppingTest(tf.test.TestCase):
n_classes=3, n_classes=3,
steps=1000) 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)) score2 = accuracy_score(y_test, classifier2.predict(X_test))
# self.assertGreater(score2, score1, "No improvement using early stopping.") # self.assertGreater(score2, score1, "No improvement using early stopping.")

View File

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

View File

@ -33,10 +33,10 @@ class SaverTest(tf.test.TestCase):
classifier = learn.TensorFlowLinearClassifier(n_classes=3) classifier = learn.TensorFlowLinearClassifier(n_classes=3)
classifier.fit(iris.data, iris.target) classifier.fit(iris.data, iris.target)
classifier.save(path) classifier.save(path)
new_classifier = learn.TensorFlowEstimator.restore(path) # new_classifier = learn.TensorFlowEstimator.restore(path)
self.assertEqual(type(new_classifier), type(classifier)) # self.assertEqual(type(new_classifier), type(classifier))
score = accuracy_score(iris.target, new_classifier.predict(iris.data)) # score = accuracy_score(iris.target, new_classifier.predict(iris.data))
self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score)) # self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score))
def testCustomModel(self): def testCustomModel(self):
path = tf.test.get_temp_dir() + '/tmp.saver2' 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 = learn.TensorFlowEstimator(model_fn=custom_model, n_classes=3)
classifier.fit(iris.data, iris.target) classifier.fit(iris.data, iris.target)
classifier.save(path) classifier.save(path)
new_classifier = learn.TensorFlowEstimator.restore(path) # new_classifier = learn.TensorFlowEstimator.restore(path)
self.assertEqual(type(new_classifier), type(classifier)) # self.assertEqual(type(new_classifier), type(classifier))
score = accuracy_score(iris.target, new_classifier.predict(iris.data)) # score = accuracy_score(iris.target, new_classifier.predict(iris.data))
self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score)) # self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score))
def testDNN(self): def testDNN(self):
path = tf.test.get_temp_dir() + '/tmp_saver3' path = tf.test.get_temp_dir() + '/tmp_saver3'
@ -62,10 +62,10 @@ class SaverTest(tf.test.TestCase):
n_classes=3) n_classes=3)
classifier.fit(iris.data, iris.target) classifier.fit(iris.data, iris.target)
classifier.save(path) classifier.save(path)
new_classifier = learn.TensorFlowEstimator.restore(path) # new_classifier = learn.TensorFlowEstimator.restore(path)
self.assertEqual(type(new_classifier), type(classifier)) # self.assertEqual(type(new_classifier), type(classifier))
score = accuracy_score(iris.target, new_classifier.predict(iris.data)) # score = accuracy_score(iris.target, new_classifier.predict(iris.data))
self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score)) # self.assertGreater(score, 0.5, 'Failed with score = {0}'.format(score))
def testNoFolder(self): def testNoFolder(self):
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
@ -80,7 +80,7 @@ class SaverTest(tf.test.TestCase):
classifier.fit(iris.data, iris.target) classifier.fit(iris.data, iris.target)
classifier.save(path) classifier.save(path)
os.remove(os.path.join(path, 'checkpoint')) os.remove(os.path.join(path, 'checkpoint'))
with self.assertRaises(ValueError): with self.assertRaises(NotImplementedError):
learn.TensorFlowEstimator.restore(path) learn.TensorFlowEstimator.restore(path)
if __name__ == '__main__': 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. # Copyright 2015-present The Scikit Flow Authors. All Rights Reserved.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # 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 six.moves import xrange # pylint: disable=redefined-builtin
from tensorflow.python.platform import tf_logging as logging
def train(session, def train(session,
train_op, train_op,
@ -45,6 +50,8 @@ def train(session,
summaries: Joined object of all summaries that should be ran. summaries: Joined object of all summaries that should be ran.
feed_params_fn: Feed params function. 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): for step in xrange(steps):
feed_dict = feed_dict_fn() feed_dict = feed_dict_fn()
if summaries is not None: if summaries is not None:
@ -55,13 +62,5 @@ def train(session,
global_step_value, loss_value, _ = session.run( global_step_value, loss_value, _ = session.run(
[global_step, loss, train_op], [global_step, loss, train_op],
feed_dict=feed_dict) 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: if summaries is not None and summary_writer and summ is not None:
summary_writer.add_summary(summ, global_step_value) 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 import six
from tensorflow.python.framework import dtypes from tensorflow.python.ops import gen_io_ops
from tensorflow.python.ops import script_ops
from tensorflow.python.ops import state_ops from tensorflow.python.ops import state_ops
from tensorflow.python.ops import variable_scope as vs 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 gfile
from tensorflow.python.platform import tf_logging as logging from tensorflow.python.platform import tf_logging as logging
from tensorflow.python.training import saver from tensorflow.python.training import saver
from tensorflow.python.training import training as train 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): def load_checkpoint(filepattern):
"""Returns CheckpointReader for latest checkpoint. """Returns CheckpointReader for latest checkpoint.
@ -42,13 +49,11 @@ def load_checkpoint(filepattern):
Raises: Raises:
ValueError: if checkpoint_dir doesn't have 'checkpoint' file or checkpoints. ValueError: if checkpoint_dir doesn't have 'checkpoint' file or checkpoints.
""" """
if gfile.IsDirectory(filepattern): filename = _get_checkpoint_filename(filepattern)
filename = saver.latest_checkpoint(filepattern) if filename is None:
if filename is None: raise ValueError("Couldn't find 'checkpoint' file or checkpoints in "
raise ValueError("Couldn't find 'checkpoint' file or checkpoints in " "given directory %s" % filepattern)
"given directory %s" % filepattern) return train.NewCheckpointReader(filename)
return train.NewCheckpointReader(filename)
return train.NewCheckpointReader(filepattern)
def load_variable(checkpoint_dir, name): def load_variable(checkpoint_dir, name):
@ -83,43 +88,49 @@ def list_variables(checkpoint_dir):
return result return result
def _checkpoint_initializer(variable, checkpoint_reader, tensor_name): # pylint: disable=protected-access
"""Assigns variable to value that will be loaded from checkpoint's tensor. # 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: Args:
variable: `Variable` object. 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. tensor_name: Name of the `Tensor` to load from checkpoint reader.
slice_spec: Slice specification for loading partitioned variables.
Returns: name: Name of the operation.
`Tensor` that returns value of `tensor_name` in checkpoint.
Raises:
ValueError: if shape or dtype of `variable` doesn't match with Tensor in
checkpoint.
""" """
# Currently to avoid putting the whole tensor into the graph, this adds a base_type = variable.dtype.base_dtype
# py_func function to the graph, that will return actual value. restore_op = gen_io_ops._restore_slice(
# TODO(ipolosukhin): Rewrite this as C++ op, that loads checkpoint at time. file_pattern,
tensor = checkpoint_reader.get_tensor(tensor_name) tensor_name,
def _tensor(): slice_spec,
return tensor base_type,
if not variable.get_shape().is_compatible_with(tensor.shape): preferred_shard=-1,
raise ValueError( name=name)
"Shape of variable %s (%s) doesn't match with shape of " variable._initializer_op = state_ops.assign(variable, restore_op)
"tensor %s (%s) from checkpoint reader." % (
variable.name, str(variable.get_shape()),
tensor_name, str(tensor.shape) def _set_variable_or_list_initializer(variable_or_list, file_pattern,
)) tensor_name):
if not dtypes.as_dtype(tensor.dtype).is_compatible_with(variable.dtype): if isinstance(variable_or_list, (list, tuple)):
raise ValueError( # A set of slices.
"DType of variable %s (%s) doesn't match with dtype of " slice_name = None
"tensor %s (%s) from checkpoint reader." % ( for v in variable_or_list:
variable.name, str(variable.dtype), if slice_name is None:
tensor_name, str(dtypes.as_dtype(tensor.dtype)) slice_name = v._save_slice_info.full_name
)) elif slice_name != v._save_slice_info.full_name:
return state_ops.assign( raise ValueError("Slices must all be from the same tensor: %s != %s" %
variable, script_ops.py_func(_tensor, [], [tensor.dtype])[0]) (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): 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 current `scope_name` from `checkpoint_scope_name` with matching variable
names. names.
`'scope_name/variable_name': 'checkpoint_scope_name/some_other_variable'` - `'scope_name/variable_name': 'checkpoint_scope_name/some_other_variable'` -
will initalize `scope_name/variable_name` variable will initalize `scope_name/variable_name` variable
from `checkpoint_scope_name/some_other_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: Example:
```python ```python
@ -142,13 +160,18 @@ def init_from_checkpoint(checkpoint_dir, assignment_map):
with tf.variable_scope('test'): with tf.variable_scope('test'):
m = tf.get_variable('my_var') m = tf.get_variable('my_var')
with tf.variable_scope('test2'): with tf.variable_scope('test2'):
m = tf.get_variable('my_var') var2 = tf.get_variable('my_var')
... ...
# Specify which variables to intialize from checkpoint. # Specify which variables to intialize from checkpoint.
init_from_checkpoint(checkpoint_dir, { init_from_checkpoint(checkpoint_dir, {
'test/my_var': 'some_var', 'test/my_var': 'some_var',
'test2/', 'some_scope/'}) '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. # Initialize variables as usual.
session.run(tf.get_all_variables()) 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. tf.errors.OpError: If missing checkpoints or tensors in checkpoints.
ValueError: If missing variables in current graph. ValueError: If missing variables in current graph.
""" """
filepattern = _get_checkpoint_filename(checkpoint_dir)
reader = load_checkpoint(checkpoint_dir) reader = load_checkpoint(checkpoint_dir)
variable_map = reader.get_variable_to_shape_map() variable_map = reader.get_variable_to_shape_map()
for current_name, tensor_name in six.iteritems(assignment_map): for current_name, tensor_name in six.iteritems(assignment_map):
scopes = "" scopes = ""
if "/" in current_name: var = None
scopes = current_name[:current_name.rindex("/")] # Check if this is Variable object.
current_name = current_name[current_name.rindex("/") + 1:] if isinstance(current_name, variables.Variable):
if current_name: 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 1 to 1 mapping was provided, find variable in the scope.
if tensor_name not in variable_map: if tensor_name not in variable_map:
raise ValueError("Tensor %s is not found in %s checkpoint" % ( raise ValueError("Tensor %s is not found in %s checkpoint" % (
tensor_name, checkpoint_dir tensor_name, checkpoint_dir
)) ))
with vs.variable_scope(scopes, reuse=True): if isinstance(var, variables.Variable):
var = vs.get_variable(current_name) # Additional at-call-time checks.
var._initializer_op = _checkpoint_initializer(var, reader, tensor_name) # pylint: disable=protected-access if not var.get_shape().is_compatible_with(variable_map[tensor_name]):
logging.info("Initialize variable %s from checkpoint %s with %s" % ( raise ValueError(
var.name, checkpoint_dir, tensor_name "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: else:
if "/" in current_name:
scopes = current_name[:current_name.rindex("/")]
current_name = current_name[current_name.rindex("/") + 1:]
if not tensor_name.endswith("/"): if not tensor_name.endswith("/"):
raise ValueError( raise ValueError(
"Assignment map with scope only name (%s) " "Assignment map with scope only name (%s) "
@ -191,21 +238,23 @@ def init_from_checkpoint(checkpoint_dir, assignment_map):
scopes, tensor_name scopes, tensor_name
)) ))
# If scope to scope mapping was provided, find all variables in the scope. # If scope to scope mapping was provided, find all variables in the scope.
# TODO(ipolosukhin): Refactor variable_scope module to provide nicer APIs. for var_name in var_scope._vars:
var_scope = vs._get_default_variable_store() # pylint: disable=protected-access
for var_name in var_scope._vars: # pylint: disable=protected-access
if var_name.startswith(scopes): if var_name.startswith(scopes):
# Lookup name with specified prefix and suffix from current variable. # 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: if full_tensor_name not in variable_map:
raise ValueError( raise ValueError(
"Tensor %s (%s in %s) is not found in %s checkpoint" % ( "Tensor %s (%s in %s) is not found in %s checkpoint" % (
full_tensor_name, var_name[len(scopes) + 1:], tensor_name, full_tensor_name, var_name[len(scopes) + 1:], tensor_name,
checkpoint_dir checkpoint_dir
)) ))
var = var_scope._vars[var_name] # pylint: disable=protected-access var = var_scope._vars[var_name]
var._initializer_op = _checkpoint_initializer( # pylint: disable=protected-access _set_variable_or_list_initializer(var, filepattern, full_tensor_name)
var, reader, full_tensor_name)
logging.info("Initialize variable %s from checkpoint %s with %s" % ( logging.info("Initialize variable %s from checkpoint %s with %s" % (
var_name, checkpoint_dir, tensor_name 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 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): class CheckpointsTest(tf.test.TestCase):
def testNoCheckpoints(self): def testNoCheckpoints(self):
@ -97,7 +115,7 @@ class CheckpointsTest(tf.test.TestCase):
}) })
checkpoints.init_from_checkpoint(checkpoint_dir, { checkpoints.init_from_checkpoint(checkpoint_dir, {
"some_scope/some_other_scope/my2": "var2", "some_scope/some_other_scope/my2": "var2",
"my3": "var3", my3: "var3",
}) })
session.run(tf.initialize_all_variables()) session.run(tf.initialize_all_variables())
@ -107,7 +125,60 @@ class CheckpointsTest(tf.test.TestCase):
self.assertAllEqual(my4.eval(session), v4) self.assertAllEqual(my4.eval(session), v4)
# Check that tensors are not explicitly in the graph. # 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): def testInitFromCheckpointMissing(self):
checkpoint_dir = self.get_temp_dir() checkpoint_dir = self.get_temp_dir()
@ -142,11 +213,6 @@ class CheckpointsTest(tf.test.TestCase):
checkpoints.init_from_checkpoint(checkpoint_dir, { checkpoints.init_from_checkpoint(checkpoint_dir, {
"some_scope/my1": "var1"}) "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. # Variable 'my1' and 'my2' are missing in given checkpoint scope.
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
checkpoints.init_from_checkpoint(checkpoint_dir, { 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_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_percentage_less
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_precision 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
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_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_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_precision_at_k
from tensorflow.contrib.metrics.python.ops.metric_ops import streaming_sparse_recall_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.framework import ops
from tensorflow.python.ops import array_ops from tensorflow.python.ops import array_ops
from tensorflow.python.ops import check_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 math_ops
from tensorflow.python.ops import nn from tensorflow.python.ops import nn
from tensorflow.python.ops import sparse_ops from tensorflow.python.ops import sparse_ops
@ -406,9 +405,9 @@ def streaming_precision(predictions, labels, ignore_mask=None,
Raises: Raises:
ValueError: If the dimensions of `predictions` and `labels` don't match or 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 `ignore_mask` is not `None` and its shape doesn't match `predictions`
if either `metrics_collections` or `updates_collections` are not or if either `metrics_collections` or `updates_collections` are not a list
a list or tuple. or tuple.
""" """
with variable_scope.variable_op_scope( with variable_scope.variable_op_scope(
[predictions, labels], name, 'precision'): [predictions, labels], name, 'precision'):
@ -485,9 +484,9 @@ def streaming_recall(predictions, labels, ignore_mask=None,
Raises: Raises:
ValueError: If the dimensions of `predictions` and `labels` don't match or 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 `ignore_mask` is not `None` and its shape doesn't match `predictions`
if either `metrics_collections` or `updates_collections` are not or if either `metrics_collections` or `updates_collections` are not a list
a list or tuple. or tuple.
""" """
with variable_scope.variable_op_scope([predictions, labels], name, 'recall'): with variable_scope.variable_op_scope([predictions, labels], name, 'recall'):
predictions, labels = _remove_squeezable_dimensions(predictions, labels) predictions, labels = _remove_squeezable_dimensions(predictions, labels)
@ -521,6 +520,139 @@ def streaming_recall(predictions, labels, ignore_mask=None,
return recall, update_op 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, def streaming_auc(predictions, labels, ignore_mask=None, num_thresholds=200,
metrics_collections=None, updates_collections=None, metrics_collections=None, updates_collections=None,
name=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 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 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` `true_positives`, `true_negatives`, `false_positives` and `false_negatives`
counts with the number of each found in the current `predictions` and `labels` 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 `Tensors`. If `ignore_mask` is not `None`, then the increment is performed
only the elements of `predictions` and `labels` whose corresponding value using only the elements of `predictions` and `labels` whose corresponding
in `ignore_mask` is `False`. In addition to performing the updates, value in `ignore_mask` is `False`. In addition to performing the updates,
`update_op` also returns the `auc`. `update_op` also returns the `auc`.
Args: Args:
@ -563,108 +695,27 @@ def streaming_auc(predictions, labels, ignore_mask=None, num_thresholds=200,
name: An optional variable_op_scope name. name: An optional variable_op_scope name.
Returns: 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`, update_op: An operation that increments the `true_positives`,
`true_negatives`, `false_positives` and `false_negatives` variables `true_negatives`, `false_positives` and `false_negatives` variables
appropriately and whose value matches `auc`. appropriately and whose value matches `auc`.
Raises: Raises:
ValueError: If the shape of `predictions` and `labels` do not match or if ValueError: If the shape of `predictions` and `labels` do not match or if
`weights` is not `None` and its shape doesn't match `values` `ignore_mask` is not `None` and its shape doesn't match `predictions` or
or if either `metrics_collections` or `updates_collections` are not a list if either `metrics_collections` or `updates_collections` are not a list or
or tuple. tuple.
""" """
with variable_scope.variable_op_scope([predictions, labels], name, 'auc'): with variable_scope.variable_op_scope([predictions, labels], name, 'auc'):
predictions, labels = _remove_squeezable_dimensions(predictions, labels) kepsilon = 1e-7 # to account for floating point imprecisions
predictions.get_shape().assert_is_compatible_with(labels.get_shape()) 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 (true_positives, false_negatives, true_negatives, false_positives,
logging_ops.Assert( true_positives_compute_op, false_negatives_compute_op,
math_ops.equal( true_negatives_compute_op, false_positives_compute_op) = _tp_fn_tn_fp(
array_ops.rank(predictions), 1), predictions, labels, thresholds, ignore_mask)
['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))
epsilon = 1.0e-6 epsilon = 1.0e-6
assert array_ops.squeeze( assert array_ops.squeeze(
@ -698,6 +749,149 @@ def streaming_auc(predictions, labels, ignore_mask=None, num_thresholds=200,
return auc, update_op 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, def streaming_recall_at_k(predictions, labels, k, ignore_mask=None,
metrics_collections=None, updates_collections=None, metrics_collections=None, updates_collections=None,
name=None): name=None):
@ -741,9 +935,9 @@ def streaming_recall_at_k(predictions, labels, k, ignore_mask=None,
Raises: Raises:
ValueError: If the dimensions of `predictions` and `labels` don't match or 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 if `ignore_mask` is not `None` and its shape doesn't match `predictions`
either `metrics_collections` or `updates_collections` are not a list or or if either `metrics_collections` or `updates_collections` are not a list
tuple. or tuple.
""" """
in_top_k = math_ops.to_float(nn.in_top_k(predictions, labels, k)) 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), 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) 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): class StreamingRecallAtKTest(tf.test.TestCase):
def setUp(self): def setUp(self):

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -49,7 +49,7 @@ def conv_model(X, y):
features = tf.reshape(features, [-1, 12]) features = tf.reshape(features, [-1, 12])
return learn.models.logistic_regression(features, y) 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. # Create a classifier, train and predict.
classifier = learn.TensorFlowEstimator(model_fn=conv_model, n_classes=10, classifier = learn.TensorFlowEstimator(model_fn=conv_model, n_classes=10,
steps=1000, learning_rate=0.05, 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, X_train, X_val, y_train, y_val = train_test_split(X_train, y_train,
test_size=0.2, random_state=42) test_size=0.2, random_state=42)
val_monitor = learn.monitors.ValidationMonitor(X_val, y_val, val_monitor = learn.monitors.ValidationMonitor(X_val, y_val,
early_stopping_rounds=200, early_stopping_rounds=200)
n_classes=3)
# classifier with early stopping on training data # classifier with early stopping on training data
classifier1 = learn.TensorFlowDNNClassifier(hidden_units=[10, 20, 10], classifier1 = learn.TensorFlowDNNClassifier(hidden_units=[10, 20, 10],

View File

@ -219,10 +219,17 @@ Generate `n` samples.
Base class for continuous probability distributions. Base class for continuous probability distributions.
`ContinuousDistribution` defines the API for the likelihood functions `pdf` `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 ```Normal(mu, sigma) = sigma * Normal(0, 1) + mu```
class's implementation.
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 See `BaseDistribution` for more information on the API for probability
distributions. 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. 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} #### `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} #### `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} #### `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} #### `tf.contrib.distributions.Exponential.sample(n, seed=None, name=None)` {#Exponential.sample}
Generate `n` samples. Sample `n` observations from the Exponential Distributions.
##### Args: ##### Args:
* <b>`n`</b>: scalar. Number of samples to draw from each distribution. * <b>`n`</b>: `Scalar`, type int32, the number of observations to sample.
* <b>`seed`</b>: Python integer seed for RNG * <b>`seed`</b>: Python integer, the random seed.
* <b>`name`</b>: name to give to the op. * <b>`name`</b>: The name to give this op.
##### Returns: ##### Returns:
* <b>`samples`</b>: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` * <b>`samples`</b>: `[n, ...]`, a `Tensor` of `n` samples for each
with values of type `self.dtype`. 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} #### `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. * <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} #### `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} #### `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} #### `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. * <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} #### `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 * <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 `ignore_mask` is not `None` and its shape doesn't match `predictions`
if either `metrics_collections` or `updates_collections` are not or if either `metrics_collections` or `updates_collections` are not a list
a list or tuple. 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 * <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 `ignore_mask` is not `None` and its shape doesn't match `predictions`
if either `metrics_collections` or `updates_collections` are not or if either `metrics_collections` or `updates_collections` are not a list
a list or tuple. 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 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 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` `true_positives`, `true_negatives`, `false_positives` and `false_negatives`
counts with the number of each found in the current `predictions` and `labels` 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 `Tensors`. If `ignore_mask` is not `None`, then the increment is performed
only the elements of `predictions` and `labels` whose corresponding value using only the elements of `predictions` and `labels` whose corresponding
in `ignore_mask` is `False`. In addition to performing the updates, value in `ignore_mask` is `False`. In addition to performing the updates,
`update_op` also returns the `auc`. `update_op` also returns the `auc`.
##### Args: ##### Args:
@ -347,7 +347,7 @@ in `ignore_mask` is `False`. In addition to performing the updates,
##### Returns: ##### 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`, * <b>`update_op`</b>: An operation that increments the `true_positives`,
`true_negatives`, `false_positives` and `false_negatives` variables `true_negatives`, `false_positives` and `false_negatives` variables
appropriately and whose value matches `auc`. 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 * <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` `ignore_mask` is not `None` and its shape doesn't match `predictions` or
or if either `metrics_collections` or `updates_collections` are not a list if either `metrics_collections` or `updates_collections` are not a list or
or tuple. tuple.
- - - - - -
@ -411,9 +411,9 @@ recall value.
* <b>`ValueError`</b>: If the dimensions of `predictions` and `labels` don't match or * <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 if `ignore_mask` is not `None` and its shape doesn't match `predictions`
either `metrics_collections` or `updates_collections` are not a list or or if either `metrics_collections` or `updates_collections` are not a list
tuple. 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} #### `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. Base class for continuous probability distributions.
`ContinuousDistribution` defines the API for the likelihood functions `pdf` `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 ```Normal(mu, sigma) = sigma * Normal(0, 1) + mu```
class's implementation.
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 See `BaseDistribution` for more information on the API for probability
distributions. 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. 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} #### `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} #### `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} #### `tf.contrib.distributions.Exponential.sample(n, seed=None, name=None)` {#Exponential.sample}
Generate `n` samples. Sample `n` observations from the Exponential Distributions.
##### Args: ##### Args:
* <b>`n`</b>: scalar. Number of samples to draw from each distribution. * <b>`n`</b>: `Scalar`, type int32, the number of observations to sample.
* <b>`seed`</b>: Python integer seed for RNG * <b>`seed`</b>: Python integer, the random seed.
* <b>`name`</b>: name to give to the op. * <b>`name`</b>: The name to give this op.
##### Returns: ##### Returns:
* <b>`samples`</b>: a `Tensor` of shape `(n,) + self.batch_shape + self.event_shape` * <b>`samples`</b>: `[n, ...]`, a `Tensor` of `n` samples for each
with values of type `self.dtype`. 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} #### `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. * <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} #### `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. * <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} #### `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} #### `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} #### `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. 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. 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). (class labels in classification, real numbers in regression).
* <b>`steps`</b>: number of steps to train model for. * <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>`batch_size`</b>: minibatch size to use on the input, defaults to 32.
* <b>`monitor`</b>: monitor object to print training progress and invoke * <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
early stopping. inside the training loop.
##### Returns: ##### 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. 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). (class label in classification, real numbers in regression).
* <b>`steps`</b>: number of steps to train model for. * <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>`batch_size`</b>: minibatch size to use on the input, defaults to 32.
* <b>`monitor`</b>: Monitor object to print training progress and invoke * <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
early stopping. inside the training loop.
##### Returns: ##### Returns:
@ -151,7 +158,7 @@ Returns prediction probabilities for given features (classification).
* <b>`x`</b>: features. * <b>`x`</b>: features.
* <b>`batch_size`</b>: OVerride default batch size. * <b>`batch_size`</b>: Override default batch size.
##### Returns: ##### 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. 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 * <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor. dict and Tensor.
* <b>`steps`</b>: number of steps to train model for. * <b>`steps`</b>: number of steps to train model for.
* <b>`monitor`</b>: monitor object to print training progress and invoke * <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
early stopping. inside the training loop.
##### Returns: ##### Returns:

View File

@ -15,9 +15,10 @@ Parameters:
(like tf.train.GradientDescentOptimizer). (like tf.train.GradientDescentOptimizer).
clip_gradients: clip_norm value for call to `clip_by_global_norm`. None clip_gradients: clip_norm value for call to `clip_by_global_norm`. None
denotes no gradient clipping. 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. 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). (class labels in classification, real numbers in regression).
* <b>`steps`</b>: number of steps to train model for. * <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>`batch_size`</b>: minibatch size to use on the input, defaults to 32.
* <b>`monitor`</b>: monitor object to print training progress and invoke * <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
early stopping. inside the training loop.
##### Returns: ##### 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. 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). (class label in classification, real numbers in regression).
* <b>`steps`</b>: number of steps to train model for. * <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>`batch_size`</b>: minibatch size to use on the input, defaults to 32.
* <b>`monitor`</b>: Monitor object to print training progress and invoke * <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
early stopping. inside the training loop.
##### Returns: ##### Returns:
@ -156,7 +164,7 @@ Returns prediction probabilities for given features (classification).
* <b>`x`</b>: features. * <b>`x`</b>: features.
* <b>`batch_size`</b>: OVerride default batch size. * <b>`batch_size`</b>: Override default batch size.
##### Returns: ##### 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. 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 * <b>`input_fn`</b>: Input builder function, returns tuple of dicts or
dict and Tensor. dict and Tensor.
* <b>`steps`</b>: number of steps to train model for. * <b>`steps`</b>: number of steps to train model for.
* <b>`monitor`</b>: monitor object to print training progress and invoke * <b>`monitors`</b>: List of `BaseMonitor` subclass instances. Used for callbacks
early stopping. inside the training loop.
##### Returns: ##### 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 Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -29,7 +36,7 @@ To restart learning, create new estimator.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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 iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early * <b>`steps`</b>: int, number of steps to train.
stopping 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 * <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization. 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. Incremental fit on a batch of samples.
@ -125,7 +141,7 @@ to converge, and you want to split up training into subparts.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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. Predict class or regression for X.
@ -151,7 +167,7 @@ returned.
##### Args: ##### 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. * <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. 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. Predict class probability of the input samples X.
##### Args: ##### 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 * <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. it into mini batches. By default the batch_size member variable is used.
@ -260,6 +276,26 @@ Returns
self 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_} #### `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 Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -52,7 +59,7 @@ To restart learning, create new estimator.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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 iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early * <b>`steps`</b>: int, number of steps to train.
stopping 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 * <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization. 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. Incremental fit on a batch of samples.
@ -148,7 +164,7 @@ to converge, and you want to split up training into subparts.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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. Predict class or regression for X.
@ -174,7 +190,7 @@ returned.
##### Args: ##### 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. * <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. 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. Predict class probability of the input samples X.
##### Args: ##### 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 * <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. it into mini batches. By default the batch_size member variable is used.
@ -283,6 +299,26 @@ Returns
self 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_} #### `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 Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -52,7 +59,7 @@ To restart learning, create new estimator.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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 iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early * <b>`steps`</b>: int, number of steps to train.
stopping 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 * <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization. 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. Incremental fit on a batch of samples.
@ -148,7 +164,7 @@ to converge, and you want to split up training into subparts.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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. Predict class or regression for X.
@ -174,7 +190,7 @@ returned.
##### Args: ##### 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. * <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. 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. Predict class probability of the input samples X.
##### Args: ##### 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 * <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. it into mini batches. By default the batch_size member variable is used.
@ -287,6 +303,26 @@ Returns
self 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_} #### `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 Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -52,7 +59,7 @@ To restart learning, create new estimator.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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 iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early * <b>`steps`</b>: int, number of steps to train.
stopping 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 * <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization. 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. Incremental fit on a batch of samples.
@ -148,7 +164,7 @@ to converge, and you want to split up training into subparts.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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. Predict class or regression for X.
@ -174,7 +190,7 @@ returned.
##### Args: ##### 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. * <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. 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. Predict class probability of the input samples X.
##### Args: ##### 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 * <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. it into mini batches. By default the batch_size member variable is used.
@ -256,3 +272,23 @@ Returns
self 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 Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -29,7 +36,7 @@ To restart learning, create new estimator.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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 iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early * <b>`steps`</b>: int, number of steps to train.
stopping 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 * <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization. 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. Incremental fit on a batch of samples.
@ -125,7 +141,7 @@ to converge, and you want to split up training into subparts.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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. Predict class or regression for X.
@ -151,7 +167,7 @@ returned.
##### Args: ##### 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. * <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. 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. Predict class probability of the input samples X.
##### Args: ##### 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 * <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. it into mini batches. By default the batch_size member variable is used.
@ -260,6 +276,26 @@ Returns
self 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_} #### `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 Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -29,7 +36,7 @@ To restart learning, create new estimator.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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 iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early * <b>`steps`</b>: int, number of steps to train.
stopping 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 * <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization. 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. Incremental fit on a batch of samples.
@ -125,7 +141,7 @@ to converge, and you want to split up training into subparts.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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. Predict class or regression for X.
@ -151,7 +167,7 @@ returned.
##### Args: ##### 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. * <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. 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. Predict class probability of the input samples X.
##### Args: ##### 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 * <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. it into mini batches. By default the batch_size member variable is used.
@ -264,6 +280,26 @@ Returns
self 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_} #### `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 Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -62,7 +69,7 @@ To restart learning, create new estimator.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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 iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early * <b>`steps`</b>: int, number of steps to train.
stopping 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 * <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization. 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. Incremental fit on a batch of samples.
@ -158,7 +174,7 @@ to converge, and you want to split up training into subparts.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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. Predict class or regression for X.
@ -184,7 +200,7 @@ returned.
##### Args: ##### 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. * <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. 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. Predict class probability of the input samples X.
##### Args: ##### 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 * <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. it into mini batches. By default the batch_size member variable is used.
@ -293,6 +309,26 @@ Returns
self 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_} #### `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 Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -62,7 +69,7 @@ To restart learning, create new estimator.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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 iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early * <b>`steps`</b>: int, number of steps to train.
stopping 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 * <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization. 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. Incremental fit on a batch of samples.
@ -158,7 +174,7 @@ to converge, and you want to split up training into subparts.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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. Predict class or regression for X.
@ -184,7 +200,7 @@ returned.
##### Args: ##### 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. * <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. 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. Predict class probability of the input samples X.
##### Args: ##### 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 * <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. it into mini batches. By default the batch_size member variable is used.
@ -297,6 +313,26 @@ Returns
self 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_} #### `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 Builds a neural network model given provided `model_fn` and training
data X and y. data X and y.
@ -29,7 +36,7 @@ To restart learning, create new estimator.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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 iterator that returns array of targets. The training target values
(class labels in classification, real numbers in regression). (class labels in classification, real numbers in regression).
* <b>`monitor`</b>: Monitor object to print training progress and invoke early * <b>`steps`</b>: int, number of steps to train.
stopping 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 * <b>`logdir`</b>: the directory to save the log file that can be used for
optional visualization. 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. Incremental fit on a batch of samples.
@ -125,7 +141,7 @@ to converge, and you want to split up training into subparts.
##### Args: ##### 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 iterator that returns arrays of features. The training input
samples for fitting the model. 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. Predict class or regression for X.
@ -151,7 +167,7 @@ returned.
##### Args: ##### 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. * <b>`axis`</b>: Which axis to argmax for classification.
By default axis 1 (next after batch) is used. By default axis 1 (next after batch) is used.
Use 2 for sequence predictions. 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. Predict class probability of the input samples X.
##### Args: ##### 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 * <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. it into mini batches. By default the batch_size member variable is used.
@ -264,6 +280,26 @@ Returns
self 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_} #### `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. 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`. 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 * <b>`init_op`</b>: An op that initializes the graph. If `None`, use `Supervisor`'s
default. 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>`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 * <b>`log_every_steps`</b>: Output logs regularly. The logs contain timing data and the
current loss. 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_master`</b>: The master string to use when preparing the session.
* <b>`supervisor_save_model_secs`</b>: Save a checkpoint every * <b>`supervisor_save_model_secs`</b>: Save a checkpoint every
`supervisor_save_model_secs` seconds when training. `supervisor_save_model_secs` seconds when training.
* <b>`supervisor_save_summaries_secs`</b>: Save summaries every * <b>`supervisor_save_summaries_steps`</b>: Save summaries every
`supervisor_save_summaries_secs` seconds when training. `supervisor_save_summaries_steps` seconds when training.
* <b>`feed_fn`</b>: A function that is called every iteration to produce a `feed_dict` * <b>`feed_fn`</b>: A function that is called every iteration to produce a `feed_dict`
passed to `session.run` calls. Optional. passed to `session.run` calls. Optional.
* <b>`max_steps`</b>: Train until `global_step_tensor` evaluates to this value. * <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` * <b>`fail_on_nan_loss`</b>: If true, raise `NanLossDuringTrainingError` if `loss_op`
evaluates to `NaN`. If false, continue training as if nothing happened. 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: ##### 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 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 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` `true_positives`, `true_negatives`, `false_positives` and `false_negatives`
counts with the number of each found in the current `predictions` and `labels` 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 `Tensors`. If `ignore_mask` is not `None`, then the increment is performed
only the elements of `predictions` and `labels` whose corresponding value using only the elements of `predictions` and `labels` whose corresponding
in `ignore_mask` is `False`. In addition to performing the updates, value in `ignore_mask` is `False`. In addition to performing the updates,
`update_op` also returns the `auc`. `update_op` also returns the `auc`.
##### Args: ##### Args:
@ -43,7 +43,7 @@ in `ignore_mask` is `False`. In addition to performing the updates,
##### Returns: ##### 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`, * <b>`update_op`</b>: An operation that increments the `true_positives`,
`true_negatives`, `false_positives` and `false_negatives` variables `true_negatives`, `false_positives` and `false_negatives` variables
appropriately and whose value matches `auc`. 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 * <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` `ignore_mask` is not `None` and its shape doesn't match `predictions` or
or if either `metrics_collections` or `updates_collections` are not a list if either `metrics_collections` or `updates_collections` are not a list or
or tuple. 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 * <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 `ignore_mask` is not `None` and its shape doesn't match `predictions`
if either `metrics_collections` or `updates_collections` are not or if either `metrics_collections` or `updates_collections` are not a list
a list or tuple. 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 * <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 `ignore_mask` is not `None` and its shape doesn't match `predictions`
if either `metrics_collections` or `updates_collections` are not or if either `metrics_collections` or `updates_collections` are not a list
a list or tuple. or tuple.

View File

@ -46,7 +46,7 @@ recall value.
* <b>`ValueError`</b>: If the dimensions of `predictions` and `labels` don't match or * <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 if `ignore_mask` is not `None` and its shape doesn't match `predictions`
either `metrics_collections` or `updates_collections` are not a list or or if either `metrics_collections` or `updates_collections` are not a list
tuple. 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. 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) 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 Note: `name_`, `func_` and `create_scope_now_` have a trailing underscore to
of collisions with kwargs. reduce the likelihood of collisions with kwargs.
##### Args: ##### 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 * <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. will be made unique by appending `_N` to the name.
* <b>`func_`</b>: The function to wrap. * <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_`. * <b>`**kwargs`</b>: Keyword arguments to apply to `func_`.
##### Returns: ##### Returns:
A function that will enter a `variable_scope` before calling `func_`. The A function to encapsulate a set of variables which should be created once
first time it is called, it will create a non-reusing scope so that the and reused. An enclosing scope will created, either where `make_template`
variables will be unique. On each subsequent call, it will reuse those is called, or wherever the result is called, depending on the value of
variables. `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: ##### Raises:

View File

@ -11,6 +11,6 @@ Merges all summaries collected in the default graph.
##### Returns: ##### Returns:
If no summaries were collected, returns None. Otherwise returns a scalar 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. 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`. 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`. an input that's optionally shifted using the value of the 1st element in `x`.
See: See:
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Computing_shifted_data 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: ##### Args:

View File

@ -1,6 +1,6 @@
### `tf.train.write_graph(graph_def, logdir, name, as_text=True)` {#write_graph} ### `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`. 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>`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>`name`</b>: Filename for the graph.
* <b>`as_text`</b>: If `True`, writes the graph as an ASCII proto. * <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`. 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`. an input that's optionally shifted using the value of the 1st element in `x`.
See: See:
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Computing_shifted_data 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: ##### 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. 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) 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 Note: `name_`, `func_` and `create_scope_now_` have a trailing underscore to
of collisions with kwargs. reduce the likelihood of collisions with kwargs.
##### Args: ##### 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 * <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. will be made unique by appending `_N` to the name.
* <b>`func_`</b>: The function to wrap. * <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_`. * <b>`**kwargs`</b>: Keyword arguments to apply to `func_`.
##### Returns: ##### Returns:
A function that will enter a `variable_scope` before calling `func_`. The A function to encapsulate a set of variables which should be created once
first time it is called, it will create a non-reusing scope so that the and reused. An enclosing scope will created, either where `make_template`
variables will be unique. On each subsequent call, it will reuse those is called, or wherever the result is called, depending on the value of
variables. `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: ##### Raises:

View File

@ -3078,7 +3078,7 @@ Merges all summaries collected in the default graph.
##### Returns: ##### Returns:
If no summaries were collected, returns None. Otherwise returns a scalar 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. 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} ### `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`. 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>`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>`name`</b>: Filename for the graph.
* <b>`as_text`</b>: If `True`, writes the graph as an ASCII proto. * <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, If operation needs to save some `Tensor`s to Graph collections,
put the arguments with names of the collections right before `name` argument. 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. * Tensor arguments should be either a single tensor or an iterable of tensors,
*Not a "Tensor or list 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` * Operations that take tensors as arguments should call `convert_to_tensor`
to convert non-tensor inputs into tensors if they are using C++ operations. 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: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")
load("//tensorflow/core:platform/default/build_config.bzl", "tf_proto_library_py") 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( py_library(
name = "python", name = "python",
@ -983,6 +984,7 @@ tf_py_wrap_cc(
"lib/io/py_record_writer.i", "lib/io/py_record_writer.i",
"platform/base.i", "platform/base.i",
"platform/numpy.i", "platform/numpy.i",
"training/saver_io.i",
"training/server_lib.i", "training/server_lib.i",
"util/port.i", "util/port.i",
"util/py_checkpoint_reader.i", "util/py_checkpoint_reader.i",
@ -994,12 +996,12 @@ tf_py_wrap_cc(
":py_record_writer_lib", ":py_record_writer_lib",
":python_op_gen", ":python_op_gen",
":tf_session_helper", ":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_server_lib",
"//tensorflow/core/distributed_runtime/rpc:grpc_session", "//tensorflow/core/distributed_runtime/rpc:grpc_session",
"//tensorflow/core:lib",
"//tensorflow/core/distributed_runtime:server_lib",
"//util/python:python_headers", "//util/python:python_headers",
], ] + tf_additional_lib_deps(),
) )
py_library( py_library(

View File

@ -1256,17 +1256,50 @@ class ControlFlowTest(tf.test.TestCase):
def break_run_twice(ix): def break_run_twice(ix):
def _break(): def _break():
assert not ran_once[ix]
ran_once[ix] = True ran_once[ix] = True
return tf.constant(ix) return tf.constant(ix)
return _break return _break
# Should not fail - each conditional gets called exactly once # 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))], 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) 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): def testOneOpCond(self):
with self.test_session(): with self.test_session():
v = tf.Variable(0) 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/nested_1/dummy:0", v1.name)
self.assertEqual("s1_2/nested_1/dummy:0", v3.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__": if __name__ == "__main__":
tf.test.main() tf.test.main()

View File

@ -69,8 +69,8 @@ bool _BytesToStringPiece(PyObject* obj, tensorflow::StringPiece* result) {
$1 = &temp; $1 = &temp;
} }
// C++ functions returning tensorflow::StringPiece will simply return bytes in Python, // C++ functions returning tensorflow::StringPiece will simply return bytes in
// or None if the StringPiece contained a NULL pointer. // Python, or None if the StringPiece contained a NULL pointer.
%typemap(out) tensorflow::StringPiece { %typemap(out) tensorflow::StringPiece {
if ($1.data()) { if ($1.data()) {
$result = PyBytes_FromStringAndSize($1.data(), $1.size()); $result = PyBytes_FromStringAndSize($1.data(), $1.size());
@ -79,3 +79,30 @@ bool _BytesToStringPiece(PyObject* obj, tensorflow::StringPiece* result) {
$result = Py_None; $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): for i, p in enumerate(preds):
with ops.name_scope("not_%d" % i): with ops.name_scope("not_%d" % i):
not_preds.append(math_ops.logical_not(p)) not_preds.append(math_ops.logical_not(p))
and_not_preds = [constant_op.constant(True, name="and_not_true")] and_not_preds = [constant_op.constant(True, name="always_true")]
for i, notp in enumerate(not_preds[:-1]): for i, notp in enumerate(not_preds):
with ops.name_scope("and_not_%d" % i): with ops.name_scope("and_not_%d" % i):
and_not_preds.append(math_ops.logical_and(and_not_preds[-1], notp)) and_not_preds.append(math_ops.logical_and(and_not_preds[-1], notp))
# preds = [p1, p2, p3] # preds = [p1, p2, p3]
# fns = [f1, f2, f3] # fns = [f1, f2, f3]
# not_preds = [~p1, ~p2, ~p3] # not_preds = [~p1, ~p2, ~p3]
# case_preds = [p1 & True, # and_not_preds = [True, ~p1, ~p1 & ~p2, ~p1 & ~p2 & ~p3]
# case_preds = [p1,
# p2 & ~p1, # p2 & ~p1,
# p3 & ~p1 & ~ p2] # p3 & ~p2 & ~p1,
# ~p3 & ~p2 & ~p1]
case_preds = [] 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): with ops.name_scope("case_%d" % i):
case_preds.append(math_ops.logical_and(p, and_not_p_prev)) 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: if exclusive:
# TODO(ebrevdo): Add Where() for DT_BOOL, replace with Size(Where(preds))
preds_c = array_ops.pack(preds, name="preds_c") preds_c = array_ops.pack(preds, name="preds_c")
num_true_conditions = math_ops.reduce_sum( num_true_conditions = math_ops.reduce_sum(
math_ops.cast(preds_c, dtypes.int32), name="num_true_conds") 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([ with ops.control_dependencies([
logging_ops.Assert(condition=at_most_one_true_condition, logging_ops.Assert(condition=at_most_one_true_condition,
data=error_msg, summarize=len(preds))]): data=error_msg, summarize=len(preds))]):
prev_case_seq = None case_seq = _build_case()
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)
else: else:
prev_case_seq = None case_seq = _build_case()
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)
return prev_case_seq return case_seq
ops.RegisterShape("Enter")(common_shapes.unchanged_shape) ops.RegisterShape("Enter")(common_shapes.unchanged_shape)

View File

@ -261,7 +261,7 @@ def merge_all_summaries(key=ops.GraphKeys.SUMMARIES):
Returns: Returns:
If no summaries were collected, returns None. Otherwise returns a scalar 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. buffer resulting from the merging.
""" """
summary_ops = ops.get_collection(key) summary_ops = ops.get_collection(key)
@ -271,6 +271,30 @@ def merge_all_summaries(key=ops.GraphKeys.SUMMARIES):
return merge_summary(summary_ops) 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): def scalar_summary(tags, values, collections=None, name=None):
"""Outputs a `Summary` protocol buffer with scalar values. """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) 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`. """Calculate the sufficient statistics for the mean and variance of `x`.
These sufficient statistics are computed using the one pass algorithm on 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`. an input that's optionally shifted using the value of the 1st element in `x`.
See: See:
https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Computing_shifted_data 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: Args:
x: A `Tensor`. x: A `Tensor`.

View File

@ -752,6 +752,41 @@ def _calc_conv_weight_params(graph, node):
filter_in_depth * filter_out_depth)) 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") @ops.RegisterShape("Conv3D")
def _Conv3DShape(op): def _Conv3DShape(op):
"""Shape function for Conv3D.""" """Shape function for Conv3D."""

View File

@ -57,9 +57,9 @@ def add_check_numerics_ops():
""" """
check_op = [] check_op = []
# This code relies on the ordering of ops in get_operations(). # 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 # 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 op in ops.get_default_graph().get_operations():
for output in op.outputs: for output in op.outputs:
if output.dtype in [dtypes.float16, dtypes.float32, dtypes.float64]: 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"] __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. """Given an arbitrary function, wrap it so that it does variable sharing.
This wraps `func_` in a Template and partially evaluates it. Templates are 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) 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 Note: `name_`, `func_` and `create_scope_now_` have a trailing underscore to
of collisions with kwargs. reduce the likelihood of collisions with kwargs.
Args: Args:
name_: A name for the scope created by this template. If necessary, the name name_: A name for the scope created by this template. If necessary, the name
will be made unique by appending `_N` to the name. will be made unique by appending `_N` to the name.
func_: The function to wrap. 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_`. **kwargs: Keyword arguments to apply to `func_`.
Returns: Returns:
A function that will enter a `variable_scope` before calling `func_`. The A function to encapsulate a set of variables which should be created once
first time it is called, it will create a non-reusing scope so that the and reused. An enclosing scope will created, either where `make_template`
variables will be unique. On each subsequent call, it will reuse those is called, or wherever the result is called, depending on the value of
variables. `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: Raises:
ValueError: if the name is None. ValueError: if the name is None.
""" """
if kwargs: if kwargs:
func_ = functools.partial(func_, **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): 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 Templates are functions that create variables the first time they are called
and reuse them thereafter. See `make_template` for full documentation. 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. """Creates a template for the given function.
Args: Args:
@ -148,6 +161,15 @@ class Template(object):
name will be made unique by appending `_N` to the it (see how name will be made unique by appending `_N` to the it (see how
`tf.variable_op_scope` treats the `default_name` for details). `tf.variable_op_scope` treats the `default_name` for details).
func: The function to apply each time. 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: Raises:
ValueError: if the name is None. ValueError: if the name is None.
@ -157,7 +179,14 @@ class Template(object):
self._name = name self._name = name
if name is None: if name is None:
raise ValueError("name cannot be 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): def _call_func(self, args, kwargs, check_for_new_variables):
try: try:
@ -204,12 +233,23 @@ class Template(object):
raise raise
def __call__(self, *args, **kwargs): 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: if self._var_scope:
with variable_scope.variable_scope(self._var_scope, reuse=True): if self._variables_created:
return self._call_func(args, kwargs, check_for_new_variables=True) # 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: 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: with variable_scope.variable_op_scope([], None, self._name) as vs:
self._var_scope = vs self._var_scope = vs
return self._call_func(args, kwargs, check_for_new_variables=False) 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