Commit 10f55570 authored by Yuxin Wu's avatar Yuxin Wu

some docs change

parent 74e3eeef
# Dataflow
Dataflow is a unified interface to produce data.
Dataflow is an interface to produce data.
A Dataflow has a `get_data()` generator method,
which yields a `datapoint` when called.
A datapoint must be a **list** of Python objects which I called the `components` of this datapoint.
For example, to train on MNIST dataset, you can build a Dataflow
that produces datapoints of two elements (components):
that yields datapoints of two elements (components):
a numpy array of shape (64, 28, 28), and an array of shape (64,).
### Composition of DataFlow
......
......@@ -20,7 +20,7 @@ You'll definitely need to tune the parameters (#processes, #threads, size of buf
or change the pipeline for new tasks and new machines to achieve best performance.
This tutorial is quite complicated, because you do need these knowledge of hardware & system to run fast on ImageNet-sized dataset.
However, for small datasets (e.g., several GBs), a proper prefetch should work well enough.
However, for __small datasets__ (e.g., several GBs), a proper prefetch should work well enough.
## Random Read
......@@ -32,9 +32,15 @@ ds1 = BatchData(ds0, 256, use_list=True)
TestDataSpeed(ds1).start_test()
```
Here `ds0` simply reads original images from filesystem, and `ds1` batch them, so
that we can measure the speed of this DataFlow in terms of "batch per second". By default `BatchData`
will concatenate the data into an `numpy.ndarray`, but since images are originally of different shapes, we use
Here `ds0` simply reads original images from filesystem. It is implemented simply by:
```python
for filename, label in filelist:
yield [cv2.imread(filename), label]
```
And `ds1` batch the datapoints from `ds0`, so that we can measure the speed of this DataFlow in terms of "batch per second".
By default `BatchData`
will stack the datapoints into an `numpy.ndarray`, but since images are originally of different shapes, we use
`use_list=True` so that it just produces lists.
On an SSD you probably can already observe good speed here (e.g. 5 it/s, that is 1280 samples/s), but on HDD the speed may be just 1 it/s,
......
......@@ -69,7 +69,7 @@ class Model(ModelDesc):
def run_submission(cfg, output, nr):
player = get_player(dumpdir=output)
predfunc = get_predict_func(cfg)
predfunc = OfflinePredictor(cfg)
logger.info("Start evaluation: ")
for k in range(nr):
if k != 0:
......
......@@ -259,7 +259,7 @@ def run_image(model, sess_init, inputs):
input_names=['input'],
output_names=['output']
)
predict_func = get_predict_func(pred_config)
predict_func = OfflinePredictor(pred_config)
meta = dataset.ILSVRCMeta()
pp_mean = meta.get_per_pixel_mean()
pp_mean_224 = pp_mean[16:-16, 16:-16, :]
......
......@@ -129,7 +129,7 @@ def run_image(model, sess_init, inputs):
input_names=['input'],
output_names=['output']
)
predict_func = get_predict_func(pred_config)
predict_func = OfflinePredictor(pred_config)
meta = dataset.ILSVRCMeta()
words = meta.get_synset_words_1000()
......
......@@ -192,7 +192,7 @@ def run(model_path, image_path, output):
session_init=get_model_loader(model_path),
input_names=['image'],
output_names=['output' + str(k) for k in range(1, 7)])
predict_func = get_predict_func(pred_config)
predict_func = OfflinePredictor(pred_config)
im = cv2.imread(image_path)
assert im is not None
im = cv2.resize(im, (im.shape[1] // 16 * 16, im.shape[0] // 16 * 16))
......
......@@ -118,7 +118,7 @@ def run_test(params, input):
input_names=['input'],
output_names=['prob']
)
predict_func = get_predict_func(pred_config)
predict_func = OfflinePredictor(pred_config)
prepro = get_inference_augmentor()
im = cv2.imread(input).astype('float32')
......
......@@ -6,7 +6,7 @@ import six
import tensorflow as tf
import re
from ..utils import log_deprecated
from ..utils import log_deprecated, logger
from ..utils.naming import MOVING_SUMMARY_OPS_KEY
from .tower import get_current_tower_context
from .symbolic_functions import rms
......@@ -39,9 +39,9 @@ def add_activation_summary(x, name=None):
if ctx is not None and not ctx.is_main_training_tower:
return
ndim = x.get_shape().ndims
# TODO use scalar if found ndim == 1
assert ndim >= 2, \
"Summary a scalar with histogram? Maybe use scalar instead. FIXME!"
if ndim < 2:
logger.warn("Cannot summarize scalar activation {}".format(x.name))
return
if name is None:
name = x.name
with tf.name_scope('activation-summary'):
......
......@@ -199,8 +199,7 @@ class Trainer(object):
an :class:`OnlinePredictor`.
"""
if not hasattr(self, '_predictor_factory'):
self._predictor_factory = PredictorFactory(
self.model, self.config.predict_tower)
self._predictor_factory = PredictorFactory(self)
return self._predictor_factory.get_predictor(input_names, output_names, tower)
def get_predict_funcs(self, input_names, output_names, n):
......
......@@ -6,6 +6,7 @@
import tensorflow as tf
from ..utils import SUMMARY_BACKUP_KEYS, PREDICT_TOWER
from ..tfutils.collection import freeze_collection
from ..utils.argtools import memoized
from ..tfutils import get_tensors_by_names, get_op_tensor_name
from ..predict import OnlinePredictor, build_prediction_graph
......@@ -15,14 +16,14 @@ __all__ = ['PredictorFactory']
class PredictorFactory(object):
""" Make predictors for a trainer"""
def __init__(self, model, towers):
def __init__(self, trainer):
"""
Args:
towers (list[int]): list of gpu id
"""
self.model = model
self.towers = towers
self.tower_built = False
self.model = trainer.model
self.towers = trainer.config.predict_tower
assert isinstance(self.towers, list)
def get_predictor(self, input_names, output_names, tower):
"""
......@@ -31,7 +32,6 @@ class PredictorFactory(object):
Returns:
an online predictor (which has to be used under a default session)
"""
if not self.tower_built:
self._build_predict_tower()
tower = self.towers[tower]
......@@ -54,12 +54,13 @@ class PredictorFactory(object):
output_vars = get_tensors_by_names(output_names)
return OnlinePredictor(raw_input_vars, output_vars)
@memoized
def _build_predict_tower(self):
# build_predict_tower might get called anywhere, but 'PREDICT_TOWER' should be the outermost name scope
# build_predict_tower might get called anywhere, but 'PREDICT_TOWER'
# should always be the outermost name scope
with tf.name_scope(None), \
freeze_collection(SUMMARY_BACKUP_KEYS), \
tf.variable_scope(tf.get_variable_scope(), reuse=True):
def fn(_):
self.model.build_graph(self.model.get_reused_placehdrs())
build_prediction_graph(fn, self.towers)
self.tower_built = True
......@@ -6,7 +6,6 @@ from .base import Trainer
from ..tfutils import TowerContext
from .input_data import FeedInput
from .predict import PredictorFactory
__all__ = ['SimpleTrainer']
......@@ -21,7 +20,6 @@ class SimpleTrainer(Trainer):
config (TrainConfig): the training config.
"""
super(SimpleTrainer, self).__init__(config)
self._predictor_factory = PredictorFactory(self.model, [0])
if config.dataflow is None:
self._input_method = config.data
assert isinstance(self._input_method, FeedInput), type(self._input_method)
......@@ -44,6 +42,3 @@ class SimpleTrainer(Trainer):
opt = self.config.optimizer
grads = opt.compute_gradients(cost_var)
self.train_op = opt.apply_gradients(grads, name='min_op')
def get_predict_func(self, input_names, output_names):
return self._predictor_factory.get_predictor(input_names, output_names, 0)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment