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

some docs change

parent 74e3eeef
# Dataflow # Dataflow
Dataflow is a unified interface to produce data. Dataflow is an interface to produce data.
A Dataflow has a `get_data()` generator method, A Dataflow has a `get_data()` generator method,
which yields a `datapoint` when called. which yields a `datapoint` when called.
A datapoint must be a **list** of Python objects which I called the `components` of this datapoint. 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 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,). a numpy array of shape (64, 28, 28), and an array of shape (64,).
### Composition of DataFlow ### Composition of DataFlow
......
...@@ -20,7 +20,7 @@ You'll definitely need to tune the parameters (#processes, #threads, size of buf ...@@ -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. 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. 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 ## Random Read
...@@ -32,9 +32,15 @@ ds1 = BatchData(ds0, 256, use_list=True) ...@@ -32,9 +32,15 @@ ds1 = BatchData(ds0, 256, use_list=True)
TestDataSpeed(ds1).start_test() TestDataSpeed(ds1).start_test()
``` ```
Here `ds0` simply reads original images from filesystem, and `ds1` batch them, so Here `ds0` simply reads original images from filesystem. It is implemented simply by:
that we can measure the speed of this DataFlow in terms of "batch per second". By default `BatchData` ```python
will concatenate the data into an `numpy.ndarray`, but since images are originally of different shapes, we use 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. `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, 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): ...@@ -69,7 +69,7 @@ class Model(ModelDesc):
def run_submission(cfg, output, nr): def run_submission(cfg, output, nr):
player = get_player(dumpdir=output) player = get_player(dumpdir=output)
predfunc = get_predict_func(cfg) predfunc = OfflinePredictor(cfg)
logger.info("Start evaluation: ") logger.info("Start evaluation: ")
for k in range(nr): for k in range(nr):
if k != 0: if k != 0:
......
...@@ -259,7 +259,7 @@ def run_image(model, sess_init, inputs): ...@@ -259,7 +259,7 @@ def run_image(model, sess_init, inputs):
input_names=['input'], input_names=['input'],
output_names=['output'] output_names=['output']
) )
predict_func = get_predict_func(pred_config) predict_func = OfflinePredictor(pred_config)
meta = dataset.ILSVRCMeta() meta = dataset.ILSVRCMeta()
pp_mean = meta.get_per_pixel_mean() pp_mean = meta.get_per_pixel_mean()
pp_mean_224 = pp_mean[16:-16, 16:-16, :] pp_mean_224 = pp_mean[16:-16, 16:-16, :]
......
...@@ -129,7 +129,7 @@ def run_image(model, sess_init, inputs): ...@@ -129,7 +129,7 @@ def run_image(model, sess_init, inputs):
input_names=['input'], input_names=['input'],
output_names=['output'] output_names=['output']
) )
predict_func = get_predict_func(pred_config) predict_func = OfflinePredictor(pred_config)
meta = dataset.ILSVRCMeta() meta = dataset.ILSVRCMeta()
words = meta.get_synset_words_1000() words = meta.get_synset_words_1000()
......
...@@ -192,7 +192,7 @@ def run(model_path, image_path, output): ...@@ -192,7 +192,7 @@ def run(model_path, image_path, output):
session_init=get_model_loader(model_path), session_init=get_model_loader(model_path),
input_names=['image'], input_names=['image'],
output_names=['output' + str(k) for k in range(1, 7)]) 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) im = cv2.imread(image_path)
assert im is not None assert im is not None
im = cv2.resize(im, (im.shape[1] // 16 * 16, im.shape[0] // 16 * 16)) im = cv2.resize(im, (im.shape[1] // 16 * 16, im.shape[0] // 16 * 16))
......
...@@ -118,7 +118,7 @@ def run_test(params, input): ...@@ -118,7 +118,7 @@ def run_test(params, input):
input_names=['input'], input_names=['input'],
output_names=['prob'] output_names=['prob']
) )
predict_func = get_predict_func(pred_config) predict_func = OfflinePredictor(pred_config)
prepro = get_inference_augmentor() prepro = get_inference_augmentor()
im = cv2.imread(input).astype('float32') im = cv2.imread(input).astype('float32')
......
...@@ -6,7 +6,7 @@ import six ...@@ -6,7 +6,7 @@ import six
import tensorflow as tf import tensorflow as tf
import re import re
from ..utils import log_deprecated from ..utils import log_deprecated, logger
from ..utils.naming import MOVING_SUMMARY_OPS_KEY from ..utils.naming import MOVING_SUMMARY_OPS_KEY
from .tower import get_current_tower_context from .tower import get_current_tower_context
from .symbolic_functions import rms from .symbolic_functions import rms
...@@ -39,9 +39,9 @@ def add_activation_summary(x, name=None): ...@@ -39,9 +39,9 @@ def add_activation_summary(x, name=None):
if ctx is not None and not ctx.is_main_training_tower: if ctx is not None and not ctx.is_main_training_tower:
return return
ndim = x.get_shape().ndims ndim = x.get_shape().ndims
# TODO use scalar if found ndim == 1 if ndim < 2:
assert ndim >= 2, \ logger.warn("Cannot summarize scalar activation {}".format(x.name))
"Summary a scalar with histogram? Maybe use scalar instead. FIXME!" return
if name is None: if name is None:
name = x.name name = x.name
with tf.name_scope('activation-summary'): with tf.name_scope('activation-summary'):
......
...@@ -199,8 +199,7 @@ class Trainer(object): ...@@ -199,8 +199,7 @@ class Trainer(object):
an :class:`OnlinePredictor`. an :class:`OnlinePredictor`.
""" """
if not hasattr(self, '_predictor_factory'): if not hasattr(self, '_predictor_factory'):
self._predictor_factory = PredictorFactory( self._predictor_factory = PredictorFactory(self)
self.model, self.config.predict_tower)
return self._predictor_factory.get_predictor(input_names, output_names, tower) return self._predictor_factory.get_predictor(input_names, output_names, tower)
def get_predict_funcs(self, input_names, output_names, n): def get_predict_funcs(self, input_names, output_names, n):
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
import tensorflow as tf import tensorflow as tf
from ..utils import SUMMARY_BACKUP_KEYS, PREDICT_TOWER from ..utils import SUMMARY_BACKUP_KEYS, PREDICT_TOWER
from ..tfutils.collection import freeze_collection from ..tfutils.collection import freeze_collection
from ..utils.argtools import memoized
from ..tfutils import get_tensors_by_names, get_op_tensor_name from ..tfutils import get_tensors_by_names, get_op_tensor_name
from ..predict import OnlinePredictor, build_prediction_graph from ..predict import OnlinePredictor, build_prediction_graph
...@@ -15,14 +16,14 @@ __all__ = ['PredictorFactory'] ...@@ -15,14 +16,14 @@ __all__ = ['PredictorFactory']
class PredictorFactory(object): class PredictorFactory(object):
""" Make predictors for a trainer""" """ Make predictors for a trainer"""
def __init__(self, model, towers): def __init__(self, trainer):
""" """
Args: Args:
towers (list[int]): list of gpu id towers (list[int]): list of gpu id
""" """
self.model = model self.model = trainer.model
self.towers = towers self.towers = trainer.config.predict_tower
self.tower_built = False assert isinstance(self.towers, list)
def get_predictor(self, input_names, output_names, tower): def get_predictor(self, input_names, output_names, tower):
""" """
...@@ -31,8 +32,7 @@ class PredictorFactory(object): ...@@ -31,8 +32,7 @@ class PredictorFactory(object):
Returns: Returns:
an online predictor (which has to be used under a default session) an online predictor (which has to be used under a default session)
""" """
if not self.tower_built: self._build_predict_tower()
self._build_predict_tower()
tower = self.towers[tower] tower = self.towers[tower]
placeholder_names = set([k.name for k in self.model.get_inputs_desc()]) placeholder_names = set([k.name for k in self.model.get_inputs_desc()])
...@@ -54,12 +54,13 @@ class PredictorFactory(object): ...@@ -54,12 +54,13 @@ class PredictorFactory(object):
output_vars = get_tensors_by_names(output_names) output_vars = get_tensors_by_names(output_names)
return OnlinePredictor(raw_input_vars, output_vars) return OnlinePredictor(raw_input_vars, output_vars)
@memoized
def _build_predict_tower(self): 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), \ with tf.name_scope(None), \
freeze_collection(SUMMARY_BACKUP_KEYS), \ freeze_collection(SUMMARY_BACKUP_KEYS), \
tf.variable_scope(tf.get_variable_scope(), reuse=True): tf.variable_scope(tf.get_variable_scope(), reuse=True):
def fn(_): def fn(_):
self.model.build_graph(self.model.get_reused_placehdrs()) self.model.build_graph(self.model.get_reused_placehdrs())
build_prediction_graph(fn, self.towers) build_prediction_graph(fn, self.towers)
self.tower_built = True
...@@ -6,7 +6,6 @@ from .base import Trainer ...@@ -6,7 +6,6 @@ from .base import Trainer
from ..tfutils import TowerContext from ..tfutils import TowerContext
from .input_data import FeedInput from .input_data import FeedInput
from .predict import PredictorFactory
__all__ = ['SimpleTrainer'] __all__ = ['SimpleTrainer']
...@@ -21,7 +20,6 @@ class SimpleTrainer(Trainer): ...@@ -21,7 +20,6 @@ class SimpleTrainer(Trainer):
config (TrainConfig): the training config. config (TrainConfig): the training config.
""" """
super(SimpleTrainer, self).__init__(config) super(SimpleTrainer, self).__init__(config)
self._predictor_factory = PredictorFactory(self.model, [0])
if config.dataflow is None: if config.dataflow is None:
self._input_method = config.data self._input_method = config.data
assert isinstance(self._input_method, FeedInput), type(self._input_method) assert isinstance(self._input_method, FeedInput), type(self._input_method)
...@@ -44,6 +42,3 @@ class SimpleTrainer(Trainer): ...@@ -44,6 +42,3 @@ class SimpleTrainer(Trainer):
opt = self.config.optimizer opt = self.config.optimizer
grads = opt.compute_gradients(cost_var) grads = opt.compute_gradients(cost_var)
self.train_op = opt.apply_gradients(grads, name='min_op') 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