From 576e7f477993f02c5f89919c3a9ed229fb7c50ff Mon Sep 17 00:00:00 2001 From: dangqingqing Date: Fri, 19 May 2017 16:01:40 +0800 Subject: [PATCH 01/28] Support variable-dimension for convolution operation. --- demo/sentiment/train_v2.py | 3 +- paddle/py_paddle/dataprovider_converter.py | 39 +++++++++++++++++----- python/paddle/trainer/PyDataProvider2.py | 17 ++++++++-- python/paddle/v2/data_type.py | 3 +- python/paddle/v2/tests/test_data_feeder.py | 24 +++++++++++++ 5 files changed, 73 insertions(+), 13 deletions(-) diff --git a/demo/sentiment/train_v2.py b/demo/sentiment/train_v2.py index 1c856556bd..5151444a86 100644 --- a/demo/sentiment/train_v2.py +++ b/demo/sentiment/train_v2.py @@ -103,7 +103,7 @@ def stacked_lstm_net(input_dim, if __name__ == '__main__': # init - paddle.init(use_gpu=False) + paddle.init(use_gpu=False, log_clipping=True) #data print 'load dictionary...' @@ -131,6 +131,7 @@ if __name__ == '__main__': # create optimizer adam_optimizer = paddle.optimizer.Adam( learning_rate=2e-3, + gradient_clipping_threshold=0.003, regularization=paddle.optimizer.L2Regularization(rate=8e-4), model_average=paddle.optimizer.ModelAverage(average_window=0.5)) diff --git a/paddle/py_paddle/dataprovider_converter.py b/paddle/py_paddle/dataprovider_converter.py index 7c6b835410..cfb82e92d5 100644 --- a/paddle/py_paddle/dataprovider_converter.py +++ b/paddle/py_paddle/dataprovider_converter.py @@ -17,6 +17,7 @@ import collections import swig_paddle import numpy import itertools +from functools import reduce __all__ = ['DataProviderConverter'] @@ -59,12 +60,14 @@ class IScanner(object): """ pass - def finish_pre_scan(self, argument): + def finish_pre_scan(self, argument, dat=None): """ Finish first scan pass. Allocate the memory. :param argument: Output arguments object. :type argument: swig_paddle.Arguments + :param dat: Output arguments object. + :type dat: The Python object, numpy.array or List. :return: """ pass @@ -95,17 +98,27 @@ class DenseScanner(IScanner): def __init__(self, input_type, pos): IScanner.__init__(self, input_type, pos) self.__mat__ = None + self.__shape__ = None self.__height__ = 0 def pre_scan(self, dat): self.__height__ += 1 - def finish_pre_scan(self, argument): + def finish_pre_scan(self, argument, dat=None): + self.__shape__ = numpy.array(dat).shape + if len(self.__shape__) > 3: + raise ValueError("The dimension of input is greater than 3.") + dim = reduce(lambda x, y: x * y, self.__shape__) + if len(self.__shape__) == 1: + assert dim == self.input_type.dim self.__mat__ = numpy.ndarray( - shape=(self.__height__, self.input_type.dim), dtype=numpy.float32) + shape=(self.__height__, dim), dtype=numpy.float32) self.__height__ = 0 def scan(self, dat): + if isinstance(dat, numpy.ndarray): + assert self.__shape__ == dat.shape + dat = dat.flatten() self.__mat__[self.__height__] = dat self.__height__ += 1 @@ -116,6 +129,13 @@ class DenseScanner(IScanner): m = swig_paddle.Matrix.createDenseFromNumpy(self.__mat__, True, self.data_in_gpu) argument.setSlotValue(self.pos, m) + if len(self.__shape__) > 1: + # The last-two dimenstions are the frame height and width. + # For example, the layout is CHW for 3-D feature of image. + # The H and W are the fram height and width. + h, w = self.__shape__[-2:] + argument.setSlotFrameHeight(self.pos, h) + argument.setSlotFrameWidth(self.pos, w) class SparseBinaryScanner(IScanner): @@ -166,7 +186,7 @@ class IndexScanner(IScanner): def pre_scan(self, dat): self.__idx__ += 1 - def finish_pre_scan(self, argument): + def finish_pre_scan(self, argument, dat=None): self.__ids__ = [0] * self.__idx__ self.__idx__ = 0 @@ -191,8 +211,8 @@ class SequenceScanner(IScanner): for each in dat: self.__inner_scanner__.pre_scan(each) - def finish_pre_scan(self, argument): - self.__inner_scanner__.finish_pre_scan(argument) + def finish_pre_scan(self, argument, dat=None): + self.__inner_scanner__.finish_pre_scan(argument, dat) def scan(self, dat): self.__seq__.append(self.__seq__[-1] + self.get_size(dat)) @@ -233,8 +253,11 @@ class DataProviderConverter(object): for each_step, scanner in itertools.izip(each_sample, scanners): scanner.pre_scan(each_step) - for scanner in scanners: - scanner.finish_pre_scan(argument) + # Some scanners, like dense scanner, pre-allocate memory for mini-batch + # in finish_pre_scan function. The dat[0] is used to calculate the size + # of input data. + for scanner, each_feature in itertools.izip(scanners, dat[0]): + scanner.finish_pre_scan(argument, each_feature) for each_sample in dat: for each_step, scanner in itertools.izip(each_sample, scanners): diff --git a/python/paddle/trainer/PyDataProvider2.py b/python/paddle/trainer/PyDataProvider2.py index a36f0ebfdc..7e305e2cd9 100644 --- a/python/paddle/trainer/PyDataProvider2.py +++ b/python/paddle/trainer/PyDataProvider2.py @@ -72,9 +72,16 @@ class InputType(object): def dense_slot(dim, seq_type=SequenceType.NO_SEQUENCE): """ - Dense Vector. It means the input feature is dense float vector. For example, - if the input is an image with 28*28 pixels, the input of Paddle neural - network should be a dense vector with dimension 784. + Dense Array. It means the input feature is dense array with float type. + For example, if the input is an image with 28*28 pixels, the input of + Paddle neural network could be a dense vector with dimension 784 or a + numpy array with shape (28, 28). + + For the 2-D convolution operation, each sample in one mini-batch must have + the similarly size in PaddlePaddle now. But, it supports variable-dimension + feature across mini-batch. For the variable-dimension, the param dim is not + used. While the data reader must yield numpy array and the data feeder will + set the data shape correctly. :param dim: dimension of this vector. :type dim: int @@ -135,6 +142,10 @@ sparse_binary_vector = sparse_non_value_slot sparse_vector = sparse_value_slot integer_value = index_slot +# dense_array can be used for variable-length input feature. +# Each feature is not a vector, but a multi-dimensional array. +dense_array = dense_slot + def dense_vector_sequence(dim): """ diff --git a/python/paddle/v2/data_type.py b/python/paddle/v2/data_type.py index d582f76ddf..226997465f 100644 --- a/python/paddle/v2/data_type.py +++ b/python/paddle/v2/data_type.py @@ -16,7 +16,8 @@ import paddle.trainer.PyDataProvider2 as pydp2 import_list = [ nm for nm in dir(pydp2) - if '_' in nm and nm[0] != '_' and ('value' in nm or 'vector' in nm) + if '_' in nm and nm[0] != '_' and ('value' in nm or 'vector' in nm or + 'array' in nm) ] import_list.extend(['InputType']) diff --git a/python/paddle/v2/tests/test_data_feeder.py b/python/paddle/v2/tests/test_data_feeder.py index 71eb3bf314..83da678da3 100644 --- a/python/paddle/v2/tests/test_data_feeder.py +++ b/python/paddle/v2/tests/test_data_feeder.py @@ -233,6 +233,30 @@ class DataFeederTest(unittest.TestCase): self.assertEqual(out_sparse.getSparseRowCols(i), data[i][1]) self.assertEqual(out_index[i], data[i][0]) + def test_dense_set_shape(self): + # test 2-D data + def gen_data(batch_size, shape): + data = [] + for i in xrange(batch_size): + each_sample = [] + each_sample.append(np.random.random(shape)) + data.append(each_sample) + return data + + feeder = DataFeeder([('image', data_type.dense_array(2352))], + {'image': 0}) + arg = feeder(gen_data(32, (3, 28, 28))) + h = arg.getSlotFrameHeight(0) + w = arg.getSlotFrameWidth(0) + self.assertEqual(h, 28) + self.assertEqual(w, 28) + + arg = feeder(gen_data(32, (3, 30, 32))) + h = arg.getSlotFrameHeight(0) + w = arg.getSlotFrameWidth(0) + self.assertEqual(h, 30) + self.assertEqual(w, 32) + if __name__ == '__main__': api.initPaddle("--use_gpu=0") From 6dfba39c96cd1d485fdf3686816b3d346675850a Mon Sep 17 00:00:00 2001 From: dangqingqing Date: Fri, 19 May 2017 16:17:15 +0800 Subject: [PATCH 02/28] resume file in sentiment demo. --- demo/sentiment/train_v2.py | 3 +-- python/setup.py.in | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/sentiment/train_v2.py b/demo/sentiment/train_v2.py index 5151444a86..1c856556bd 100644 --- a/demo/sentiment/train_v2.py +++ b/demo/sentiment/train_v2.py @@ -103,7 +103,7 @@ def stacked_lstm_net(input_dim, if __name__ == '__main__': # init - paddle.init(use_gpu=False, log_clipping=True) + paddle.init(use_gpu=False) #data print 'load dictionary...' @@ -131,7 +131,6 @@ if __name__ == '__main__': # create optimizer adam_optimizer = paddle.optimizer.Adam( learning_rate=2e-3, - gradient_clipping_threshold=0.003, regularization=paddle.optimizer.L2Regularization(rate=8e-4), model_average=paddle.optimizer.ModelAverage(average_window=0.5)) diff --git a/python/setup.py.in b/python/setup.py.in index 5dfb46192a..7d9438e3f8 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -18,6 +18,7 @@ setup(name='paddle', "numpy", "protobuf==${PROTOBUF_VERSION}", "matplotlib", + "opencv-python", ], packages=packages, package_dir={ From 09622b4569b7b1dd6b9a7f24f1c820624184d419 Mon Sep 17 00:00:00 2001 From: Xinghai Sun Date: Sat, 20 May 2017 16:11:14 +0800 Subject: [PATCH 03/28] Add DS2 design doc (doc/design/speech/README.md). --- doc/design/speech/README.MD | 155 ++++++++++++++++++++++++ doc/design/speech/image/ds2_network.png | Bin 0 -> 116482 bytes 2 files changed, 155 insertions(+) create mode 100644 doc/design/speech/README.MD create mode 100644 doc/design/speech/image/ds2_network.png diff --git a/doc/design/speech/README.MD b/doc/design/speech/README.MD new file mode 100644 index 0000000000..7304650e62 --- /dev/null +++ b/doc/design/speech/README.MD @@ -0,0 +1,155 @@ +# DeepSpeech2 on PaddlePaddle: Design Doc + +We are planning to build Deep Speech 2 (DS2) \[[1](#references)\], a powerful Automatic Speech Recognition (ASR) engine, on PaddlePaddle. For the first-stage plan, we have the following short-term goals: + +- Release a basic distributed implementation of DS2 on PaddlePaddle. +- Contribute a chapter of Deep Speech to PaddlePaddle Book. + +Intensive system optimization and low-latency inference library (details in \[[1](#references)\]) are not yet covered in this first-stage plan. + +## Table of Contents + +- [Tasks](#tasks) +- [Task Dependency](#task-dependency) +- [Design Details](#design-details) + - [Overview](#overview) + - [Row Convolution](#row-convolution) + - [Beam Search With CTC and LM](#beam-search-with-ctc-and-lm) +- [Future Work](#future-work) +- [References](#references) + +## Tasks + +We roughly break down the project into 14 tasks: + +1. Develop an **audio data provider**: + - Json filelist generator. + - Audio file format transformer. + - Spectrogram feature extraction, power normalization etc. + - Batch data reader with SortaGrad. + - Data augmentation (optional). + - Prepare (one or more) public English data sets & baseline. +2. Create a **simplified DS2 model configuration**: + - With only fixed-length (by padding) audio sequences (otherwise need *Task 3*). + - With only bidirectional-GRU (otherwise need *Task 4*). + - With only greedy decoder (otherwise need *Task 5, 6*). +3. Develop to support **variable-shaped** dense-vector (image) batches of input data. + - Update `DenseScanner` in `dataprovider_converter.py`, etc. +4. Develop a new **lookahead-row-convolution layer** (See \[[1](#references)\] for details): + - Lookahead convolution windows. + - Within-row convolution, without kernels shared across rows. +5. Build KenLM **language model** (5-gram) for beam search decoder: + - Use KenLM toolkit. + - Prepare the corpus & train the model. + - Create infererence interfaces (for Task 6). +6. Develop a **beam search decoder** with CTC + LM + WORDCOUNT: + - Beam search with CTC. + - Beam search with external custom scorer (e.g. LM). + - Try to design a more general beam search interface. +7. Develop a **Word Error Rate evaluator**: + - update `ctc_error_evaluator`(CER) to support WER. +8. Prepare internal dataset for Mandarin (optional): + - Dataset, baseline, evaluation details. + - Particular data preprocessing for Mandarin. + - Might need cooperating with the Speech Department. +9. Create **standard DS2 model configuration**: + - With variable-length audio sequences (need *Task 3*). + - With unidirectional-GRU + row-convolution (need *Task 4*). + - With CTC-LM beam search decoder (need *Task 5, 6*). +10. Make it run perfectly on **clusters**. +11. Experiments and **benchmarking** (for accuracy, not efficiency): + - With public English dataset. + - With internal (Baidu) Mandarin dataset (optional). +12. Time **profiling** and optimization. +13. Prepare **docs**. +14. Prepare PaddlePaddle **Book** chapter with a simplified version. + +## Task Dependency + +Tasks parallelizable within phases: + +Roadmap | Description | Parallelizable Tasks +----------- | :------------------------------------ | :-------------------- +Phase I | Simplified model & components | *Task 1* ~ *Task 8* +Phase II | Standard model & benchmarking & profiling | *Task 9* ~ *Task 12* +Phase III | Documentations | *Task13* ~ *Task14* + +Issue for each task will be created later. Contributions, discussions and comments are all highly appreciated and welcomed! + +## Design Details + +### Overview + +Traditional **ASR** (Automatic Speech Recognition) pipelines require great human efforts devoted to elaborately tuning multiple hand-engineered components (e.g. audio feature design, accoustic model, pronuncation model and language model etc.). **Deep Speech 2** (**DS2**) \[[1](#references)\], however, trains such ASR models in an end-to-end manner, replacing most intermediate modules with only a single deep network architecture. With scaling up both the data and model sizes, DS2 achieves a very significant performance boost. + +Please read Deep Speech 2 \[[1](#references),[2](#references)\] paper for more background knowledge. + +The classical DS2 network contains 15 layers (from bottom to top): + +- **Two** data layers (audio spectrogram, transcription text) +- **Three** 2D convolution layers +- **Seven** uni-directional simple-RNN layers +- **One** lookahead row convolution layers +- **One** fully-connected layers +- **One** CTC-loss layer + +
+
+Figure 1. Archetecture of Deep Speech 2 Network. +
+ +We don't have to persist on this 2-3-7-1-1-1 depth \[[2](#references)\]. Similar networks with different depths might also work well. As in \[[1](#references)\], authors use a different depth (e.g. 2-2-3-1-1-1) for final experiments. + +Key ingredients about the layers: + +- **Data Layers**: + - Frame sequences data of audio **spectrogram** (with FFT). + - Token sequences data of **transcription** text (labels). + - These two type of sequences do not have the same lengthes, thus a CTC-loss layer is required. +- **2D Convolution Layers**: + - Not only temporal convolution, but also **frequency convolution**. Like a 2D image convolution, but with a variable dimension (i.e. temporal dimension). + - With striding for only the first convlution layer. + - No pooling for all convolution layers. +- **Uni-directional RNNs** + - Uni-directional + row convolution: for low-latency inference. + - Bi-direcitional + without row convolution: if we don't care about the inference latency. +- **Row convolution**: + - For looking only a few steps ahead into the feature, instead of looking into a whole sequence in bi-directional RNNs. + - Not nessesary if with bi-direcitional RNNs. + - "**Row**" means convolutions are done within each frequency dimension (row), and no convolution kernels shared across. +- **Batch Normalization Layers**: + - Added to all above layers (except for data and loss layer). + - Sequence-wise normalization for RNNs: BatchNorm only performed on input-state projection and not state-state projection, for efficiency consideration. + + +Required Components | PaddlePaddle Support | Need to Develop +:------------------------------------- | :-------------------------------------- | :----------------------- +Data Layer I (Spectrogram) | Not supported yet. | TBD (Task 3) +Data Layer II (Transcription) | `paddle.data_type.integer_value_sequence` | - +2D Convolution Layer | `paddle.layer.image_conv_layer` | - +DataType Converter (vec2seq) | `paddle.layer.block_expand` | - +Bi-/Uni-directional RNNs | `paddle.layer.recurrent_group` | - +Row Convolution Layer | Not supported yet. | TBD (Task 4) +CTC-loss Layer | `paddle.layer.warp_ctc` | - +Batch Normalization Layer | `paddle.layer.batch_norm` | - +CTC-Beam search | Not supported yet. | TBD (Task 6) + +### Row Convolution + +TODO by Assignees + +### Beam Search with CTC and LM + +TODO by Assignees + +## Future Work + +- Efficiency Improvement +- Accuracy Improvement +- Low-latency Inference Library +- Large-scale benchmarking + +## References + +1. Dario Amodei, etc., [Deep Speech 2 : End-to-End Speech Recognition in English and Mandarin](http://proceedings.mlr.press/v48/amodei16.pdf). ICML 2016. +2. Dario Amodei, etc., [Deep Speech 2 : End-to-End Speech Recognition in English and Mandarin](https://arxiv.org/abs/1512.02595). arXiv:1512.02595. diff --git a/doc/design/speech/image/ds2_network.png b/doc/design/speech/image/ds2_network.png new file mode 100644 index 0000000000000000000000000000000000000000..1a5b2184d47928cc2849d5a7c8ea2d8cf5337e11 GIT binary patch literal 116482 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�#I22A}lSN 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 literal 0 HcmV?d00001 From 6a329f0c8c392932d2885d0ada939353b5291f19 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Wed, 24 May 2017 16:22:33 +0800 Subject: [PATCH 04/28] design doc for implementation parameters in CPP. --- doc/design/parameters_in_cpp.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 doc/design/parameters_in_cpp.md diff --git a/doc/design/parameters_in_cpp.md b/doc/design/parameters_in_cpp.md new file mode 100644 index 0000000000..4989a3d16b --- /dev/null +++ b/doc/design/parameters_in_cpp.md @@ -0,0 +1,27 @@ +# Parameters in CPP + +`Parameters` is a concept we designed in Paddle V2 API. `Parameters` is a container of parameters, and make Paddle can shared parameter between topologies. We described usages of `Parameter` in [api.md](./api.md). + +We used Python to implementation Parameters before during API design phase. There are several defects for current implementation: +* We just use `memcpy` to share Parameters between topologies, but this is very inefficient. +* We did not implement share Parameters while training is not complete. We just trigger `memcpy` when start training. + +It is necessary we implement Parameters in CPP side. However, it could be a refactorization for Paddle, because Paddle was designed for training only one topology before. In current Paddle implementation, there are three concepts associated with `Parameters`: + +1. `paddle::Parameter`. A `Parameters` is a container for `paddle::Parameter`. It is evident that we should use `paddle::Parameter` when developing `Parameters`. However, the `Parameter` class contains many functions and does not have a clear interface. It contains `create/store Parameter`, `serialize/deserialize`, `optimize(i.e SGD)`, `randomize/zero`. We just need `paddle::Parameter` just create and store `Tensors (or Matrix currently)`. We should extract functionalities of Parameter into many classes to clean Paddle CPP implementation. +2. `paddle::GradientMachine` and its sub-classes, i.e., `paddle::MultiGradientMachine`, `paddle::NeuralNetwork`. We should pass `Parameters` to `paddle::GradientMachine` when `forward/backward` to avoid `memcpy` between topologies. Also, we should handle multi-GPU/CPU training, because `forward` and `backward` would perform on multi-GPUs and multi-CPUs. `Parameters` should dispatch the parameter value to each device, and gather the parameter gradient from each device. + +3. `paddle::ParameterUpdater`. The ParameterUpdater is used to update parameters in Paddle. So `Parameters` should be used by `paddle::ParameterUpdater`, and `paddle::ParameterUpdater` should optimize `Parameters` (by SGD). + + +The step by step approach for implementation Parameters in Paddle C++ core is listed below. Each step should be a PR merged into Paddle. + +1. Clean `paddle::Parameter` interface. Extract the functionalities of `paddle::Parameter` to prepare for the implementation of Parameters. + +2. Implementation a `Parameters` class. It just stores the `paddle::Parameter` inside. Make `GradientMachine` uses `Parameters` as a class member. + +3. Make `Parameters` support Multi-CPU and Multi-GPU training to prepare for sharing `Parameter` between topologies. Because we need sharing `Parameter` between topologies, it is `Parameters`'s response to exchange Parameter between GPUs not `GradientMachine`, because `GradientMachine` only used for one topology. + +4. Make `Parameters` as an argument for `forward/backward` function, not a data member for `GradientMachine`. For example, `forward` could be `forward(const Parameters& params, ...)` and `backward` could be `backward(Parameters* params, ...)`. After this step, Paddle could share `Parameters` between topologies. + +5. `ParameterUpdater` is invoked by `GradientMachine` and `Trainer`, but it updates `Parameters`. In the end, we could change `ParameterUpdater` directly uses `Parameters` to make Paddle implementation clear. From c57e98d4fea0af85a6ceff8eb838fb0a071f2222 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Wed, 24 May 2017 16:38:32 +0800 Subject: [PATCH 05/28] Refine english --- doc/design/parameters_in_cpp.md | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/doc/design/parameters_in_cpp.md b/doc/design/parameters_in_cpp.md index 4989a3d16b..357c057897 100644 --- a/doc/design/parameters_in_cpp.md +++ b/doc/design/parameters_in_cpp.md @@ -2,26 +2,38 @@ `Parameters` is a concept we designed in Paddle V2 API. `Parameters` is a container of parameters, and make Paddle can shared parameter between topologies. We described usages of `Parameter` in [api.md](./api.md). -We used Python to implementation Parameters before during API design phase. There are several defects for current implementation: +We used Python to implement Parameters when disigning V2 API before. There are several defects for current implementation: * We just use `memcpy` to share Parameters between topologies, but this is very inefficient. -* We did not implement share Parameters while training is not complete. We just trigger `memcpy` when start training. +* We did not implement share Parameters while training. We just trigger `memcpy` when start training. -It is necessary we implement Parameters in CPP side. However, it could be a refactorization for Paddle, because Paddle was designed for training only one topology before. In current Paddle implementation, there are three concepts associated with `Parameters`: +It is necessary that we implement Parameters in CPP side. However, it could be a refactorization for Paddle, because Paddle was designed for training only one topology before, i.e., each GradientMachine contains its Parameter as a data member. In current Paddle implementation, there are three concepts associated with `Parameters`: -1. `paddle::Parameter`. A `Parameters` is a container for `paddle::Parameter`. It is evident that we should use `paddle::Parameter` when developing `Parameters`. However, the `Parameter` class contains many functions and does not have a clear interface. It contains `create/store Parameter`, `serialize/deserialize`, `optimize(i.e SGD)`, `randomize/zero`. We just need `paddle::Parameter` just create and store `Tensors (or Matrix currently)`. We should extract functionalities of Parameter into many classes to clean Paddle CPP implementation. -2. `paddle::GradientMachine` and its sub-classes, i.e., `paddle::MultiGradientMachine`, `paddle::NeuralNetwork`. We should pass `Parameters` to `paddle::GradientMachine` when `forward/backward` to avoid `memcpy` between topologies. Also, we should handle multi-GPU/CPU training, because `forward` and `backward` would perform on multi-GPUs and multi-CPUs. `Parameters` should dispatch the parameter value to each device, and gather the parameter gradient from each device. +1. `paddle::Parameter`. A `Parameters` is a container for `paddle::Parameter`. +It is evident that we should use `paddle::Parameter` when developing `Parameters`. +However, the `Parameter` class contains many functions and does not have a clear interface. +It contains `create/store Parameter`, `serialize/deserialize`, `optimize(i.e SGD)`, `randomize/zero`. +When we developing `Parameters`, we only use `create/store Parameter` functionality. +We should extract functionalities of Parameter into many classes to clean Paddle CPP implementation. -3. `paddle::ParameterUpdater`. The ParameterUpdater is used to update parameters in Paddle. So `Parameters` should be used by `paddle::ParameterUpdater`, and `paddle::ParameterUpdater` should optimize `Parameters` (by SGD). +2. `paddle::GradientMachine` and its sub-classes, e.g., `paddle::MultiGradientMachine`, `paddle::NeuralNetwork`. +We should pass `Parameters` to `paddle::GradientMachine` when `forward/backward` to avoid `memcpy` between topologies. +Also, we should handle multi-GPU/CPU training, because `forward` and `backward` would perform on multi-GPUs and multi-CPUs. +`Parameters` should dispatch the parameter value to each device, and gather the parameter gradient from each device. +3. `paddle::ParameterUpdater`. The ParameterUpdater is used to update parameters in Paddle. +So `Parameters` should be used by `paddle::ParameterUpdater`, and `paddle::ParameterUpdater` should optimize `Parameters` (by SGD). -The step by step approach for implementation Parameters in Paddle C++ core is listed below. Each step should be a PR merged into Paddle. + +The step by step approach for implementation Parameters in Paddle C++ core is listed below. Each step should be a PR and could be merged into Paddle one by one. 1. Clean `paddle::Parameter` interface. Extract the functionalities of `paddle::Parameter` to prepare for the implementation of Parameters. 2. Implementation a `Parameters` class. It just stores the `paddle::Parameter` inside. Make `GradientMachine` uses `Parameters` as a class member. -3. Make `Parameters` support Multi-CPU and Multi-GPU training to prepare for sharing `Parameter` between topologies. Because we need sharing `Parameter` between topologies, it is `Parameters`'s response to exchange Parameter between GPUs not `GradientMachine`, because `GradientMachine` only used for one topology. +3. Make `Parameters` support Multi-CPU and Multi-GPU training to prepare for sharing `Parameter` between topologies. +Because we need share `Parameters` between topologies, it is `Parameters`'s response to exchange Parameters between GPUs. +`GradientMachine` should not handle how to exchange Parameters because `GradientMachine` only used to train one topology and we need to support train many topologies in Paddle, i.e., there could be many GradientMachines use one `Parameters`. 4. Make `Parameters` as an argument for `forward/backward` function, not a data member for `GradientMachine`. For example, `forward` could be `forward(const Parameters& params, ...)` and `backward` could be `backward(Parameters* params, ...)`. After this step, Paddle could share `Parameters` between topologies. -5. `ParameterUpdater` is invoked by `GradientMachine` and `Trainer`, but it updates `Parameters`. In the end, we could change `ParameterUpdater` directly uses `Parameters` to make Paddle implementation clear. +5. `ParameterUpdater` is invoked by `GradientMachine` and `Trainer`, but it updates `Parameters`. In the end of this refactorization, we could change `ParameterUpdater` directly uses `Parameters` to make `ParameterUpdater`'s implementation clear. From bb777f8e4abc8e4e191074864a1851fe1d725fe4 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Wed, 24 May 2017 16:44:14 +0800 Subject: [PATCH 06/28] Refine English --- doc/design/parameters_in_cpp.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/design/parameters_in_cpp.md b/doc/design/parameters_in_cpp.md index 357c057897..d603de3114 100644 --- a/doc/design/parameters_in_cpp.md +++ b/doc/design/parameters_in_cpp.md @@ -6,7 +6,7 @@ We used Python to implement Parameters when disigning V2 API before. There are s * We just use `memcpy` to share Parameters between topologies, but this is very inefficient. * We did not implement share Parameters while training. We just trigger `memcpy` when start training. -It is necessary that we implement Parameters in CPP side. However, it could be a refactorization for Paddle, because Paddle was designed for training only one topology before, i.e., each GradientMachine contains its Parameter as a data member. In current Paddle implementation, there are three concepts associated with `Parameters`: +It is necessary that we implement Parameters in CPP side. However, it could be a code refactoring for Paddle, because Paddle was designed for training only one topology before, i.e., each GradientMachine contains its Parameter as a data member. In current Paddle implementation, there are three concepts associated with `Parameters`: 1. `paddle::Parameter`. A `Parameters` is a container for `paddle::Parameter`. It is evident that we should use `paddle::Parameter` when developing `Parameters`. @@ -36,4 +36,4 @@ Because we need share `Parameters` between topologies, it is `Parameters`'s resp 4. Make `Parameters` as an argument for `forward/backward` function, not a data member for `GradientMachine`. For example, `forward` could be `forward(const Parameters& params, ...)` and `backward` could be `backward(Parameters* params, ...)`. After this step, Paddle could share `Parameters` between topologies. -5. `ParameterUpdater` is invoked by `GradientMachine` and `Trainer`, but it updates `Parameters`. In the end of this refactorization, we could change `ParameterUpdater` directly uses `Parameters` to make `ParameterUpdater`'s implementation clear. +5. `ParameterUpdater` is invoked by `GradientMachine` and `Trainer`, but it updates `Parameters`. In the end of this code refactoring, we could change `ParameterUpdater` directly uses `Parameters` to make `ParameterUpdater`'s implementation clear. From 27c70f39ec3917cb72b63a0dd7ccec08abb494fa Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Wed, 24 May 2017 16:51:24 +0800 Subject: [PATCH 07/28] typo --- doc/design/parameters_in_cpp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/design/parameters_in_cpp.md b/doc/design/parameters_in_cpp.md index d603de3114..4c0dcc1823 100644 --- a/doc/design/parameters_in_cpp.md +++ b/doc/design/parameters_in_cpp.md @@ -2,7 +2,7 @@ `Parameters` is a concept we designed in Paddle V2 API. `Parameters` is a container of parameters, and make Paddle can shared parameter between topologies. We described usages of `Parameter` in [api.md](./api.md). -We used Python to implement Parameters when disigning V2 API before. There are several defects for current implementation: +We used Python to implement Parameters when designing V2 API before. There are several defects for current implementation: * We just use `memcpy` to share Parameters between topologies, but this is very inefficient. * We did not implement share Parameters while training. We just trigger `memcpy` when start training. From b098ef69a4a45efa8011a2f4b93ee55eca4bcc26 Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Wed, 24 May 2017 19:26:39 +0800 Subject: [PATCH 08/28] "remove the rar extractfile, prevent small files" --- python/paddle/v2/dataset/__init__.py | 3 ++- python/paddle/v2/dataset/mq2007.py | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/python/paddle/v2/dataset/__init__.py b/python/paddle/v2/dataset/__init__.py index 80ff6295c3..26252d5bbd 100644 --- a/python/paddle/v2/dataset/__init__.py +++ b/python/paddle/v2/dataset/__init__.py @@ -24,8 +24,9 @@ import conll05 import uci_housing import sentiment import wmt14 +import mq2007 __all__ = [ 'mnist', 'imikolov', 'imdb', 'cifar', 'movielens', 'conll05', 'sentiment' - 'uci_housing', 'wmt14' + 'uci_housing', 'wmt14', 'mq2007' ] diff --git a/python/paddle/v2/dataset/mq2007.py b/python/paddle/v2/dataset/mq2007.py index fd71b34166..d8c9918d14 100644 --- a/python/paddle/v2/dataset/mq2007.py +++ b/python/paddle/v2/dataset/mq2007.py @@ -41,9 +41,7 @@ def __initialize_meta_info__(): """ fn = fetch() rar = rarfile.RarFile(fn) - dirpath = os.path.dirname(fn) - rar.extractall(path=dirpath) - return dirpath + return rar class Query(object): @@ -273,7 +271,7 @@ def load_from_text(filepath, shuffle=True, fill_missing=-1): querylists = [] querylist = None fn = __initialize_meta_info__() - with open(os.path.join(fn, filepath)) as f: + with fn.open(os.path.join(fn, filepath)) as f: for line in f: query = Query() query = query._parse_(line) From 6e91ebc0dd9dbb2ce9142216a1aa0c4575f350eb Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Wed, 24 May 2017 19:30:27 +0800 Subject: [PATCH 09/28] "remove extrafile" --- python/paddle/v2/dataset/mq2007.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/paddle/v2/dataset/mq2007.py b/python/paddle/v2/dataset/mq2007.py index d8c9918d14..fd71b34166 100644 --- a/python/paddle/v2/dataset/mq2007.py +++ b/python/paddle/v2/dataset/mq2007.py @@ -41,7 +41,9 @@ def __initialize_meta_info__(): """ fn = fetch() rar = rarfile.RarFile(fn) - return rar + dirpath = os.path.dirname(fn) + rar.extractall(path=dirpath) + return dirpath class Query(object): @@ -271,7 +273,7 @@ def load_from_text(filepath, shuffle=True, fill_missing=-1): querylists = [] querylist = None fn = __initialize_meta_info__() - with fn.open(os.path.join(fn, filepath)) as f: + with open(os.path.join(fn, filepath)) as f: for line in f: query = Query() query = query._parse_(line) From f9eb4b74b2d572f1237d7fdecb5ac7f4bc02f22f Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Wed, 24 May 2017 20:22:16 +0800 Subject: [PATCH 10/28] "update python package" --- .travis.yml | 2 +- Dockerfile | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 387367a230..2dad0e77e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,7 +48,7 @@ before_install: - if [[ "$JOB" == "PRE_COMMIT" ]]; then sudo ln -s /usr/bin/clang-format-3.8 /usr/bin/clang-format; fi # Paddle is using protobuf 3.1 currently. Protobuf 3.2 breaks the compatibility. So we specify the python # protobuf version. - - pip install numpy wheel 'protobuf==3.1' sphinx==1.5.6 recommonmark sphinx-rtd-theme==0.1.9 virtualenv pre-commit requests==2.9.2 LinkChecker + - pip install numpy wheel 'protobuf==3.1' sphinx==1.5.6 recommonmark sphinx-rtd-theme==0.1.9 virtualenv pre-commit requests==2.9.2 LinkChecker rarfile - | function timeout() { perl -e 'alarm shift; exec @ARGV' "$@"; } script: diff --git a/Dockerfile b/Dockerfile index 571c3e1476..b6f99ca539 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,7 +56,8 @@ RUN pip install --upgrade pip && \ pip install -U docopt PyYAML sphinx && \ pip install -U sphinx-rtd-theme==0.1.9 recommonmark && \ pip install pre-commit 'requests==2.9.2' 'ipython==5.3.0' && \ - pip install 'ipykernel==4.6.0' 'jupyter==1.0.0' + pip install 'ipykernel==4.6.0' 'jupyter==1.0.0' && \ + pip install rarfile # To fix https://github.com/PaddlePaddle/Paddle/issues/1954, we use # the solution in https://urllib3.readthedocs.io/en/latest/user-guide.html#ssl-py2 From d3bf8ca161a73f3355f38c8ea8f6355cde1c5349 Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Wed, 24 May 2017 22:00:45 +0800 Subject: [PATCH 11/28] "fix travis failed on rarfile " --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2dad0e77e6..44b755ee32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -48,7 +48,8 @@ before_install: - if [[ "$JOB" == "PRE_COMMIT" ]]; then sudo ln -s /usr/bin/clang-format-3.8 /usr/bin/clang-format; fi # Paddle is using protobuf 3.1 currently. Protobuf 3.2 breaks the compatibility. So we specify the python # protobuf version. - - pip install numpy wheel 'protobuf==3.1' sphinx==1.5.6 recommonmark sphinx-rtd-theme==0.1.9 virtualenv pre-commit requests==2.9.2 LinkChecker rarfile + - pip install numpy wheel 'protobuf==3.1' sphinx==1.5.6 recommonmark sphinx-rtd-theme==0.1.9 virtualenv pre-commit requests==2.9.2 LinkChecker + - pip install rarfile - | function timeout() { perl -e 'alarm shift; exec @ARGV' "$@"; } script: From 8ecd722958a182e923a5476cbb5a9dff0ce7deb8 Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Wed, 24 May 2017 23:06:33 +0800 Subject: [PATCH 12/28] "update setup.in" --- python/setup.py.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/setup.py.in b/python/setup.py.in index 5dfb46192a..1afaffd261 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -1,5 +1,6 @@ from setuptools import setup + packages=['paddle', 'paddle.proto', 'paddle.trainer', @@ -18,6 +19,7 @@ setup(name='paddle', "numpy", "protobuf==${PROTOBUF_VERSION}", "matplotlib", + "rarfile" ], packages=packages, package_dir={ From 8813ad9d2f4bfed97e2e24a5e20fa4b6db561a50 Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Thu, 25 May 2017 11:26:38 +0800 Subject: [PATCH 13/28] "fix dependency build failed" --- paddle/scripts/run_python_tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paddle/scripts/run_python_tests.sh b/paddle/scripts/run_python_tests.sh index 02d2cdb977..c588b9e08d 100755 --- a/paddle/scripts/run_python_tests.sh +++ b/paddle/scripts/run_python_tests.sh @@ -29,7 +29,7 @@ if [ $USE_VIRTUALENV_FOR_TEST -ne 0 ]; then fi export PYTHONPATH=$SCRIPTPATH/../../python/ -$PYTHON -m pip install $SCRIPTPATH/../dist/*.whl requests matplotlib opencv-python ipython==5.3 +$PYTHON -m pip install $SCRIPTPATH/../dist/*.whl requests matplotlib opencv-python ipython==5.3 rarfile for fn in "$@" do From f170111031b1f202effea678ebb5eaa4a9bf13bb Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Thu, 25 May 2017 12:18:16 +0800 Subject: [PATCH 14/28] Fix compile when not enable testing * WITH_TESTING is a flag that user could configure --- paddle/go/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/paddle/go/CMakeLists.txt b/paddle/go/CMakeLists.txt index 20f1476943..51c5252d66 100644 --- a/paddle/go/CMakeLists.txt +++ b/paddle/go/CMakeLists.txt @@ -2,8 +2,10 @@ include_directories(${CMAKE_CURRENT_BINARY_DIR}) go_library(adder SRCS adder.go) -cc_test(cgo_test +if (WITH_TESTING) + cc_test(cgo_test SRCS cgo_test.cc DEPS adder) +endif() From 19127b479c40d5f00c4310eb44e2888f52c65978 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Thu, 25 May 2017 12:16:56 +0800 Subject: [PATCH 15/28] Fix bug in run_python_tests.sh * Also, test_plot cannot run in MacOS because of matplotlib & ipython's limit. * Add missing dependency in setup.py. * fix #2264 --- cmake/util.cmake | 5 +++-- paddle/scripts/run_python_tests.sh | 9 +++++++-- python/CMakeLists.txt | 4 +++- python/paddle/v2/plot/tests/CMakeLists.txt | 6 +++++- python/setup.py.in | 1 + 5 files changed, 19 insertions(+), 6 deletions(-) diff --git a/cmake/util.cmake b/cmake/util.cmake index b828eef322..8c91434622 100644 --- a/cmake/util.cmake +++ b/cmake/util.cmake @@ -149,8 +149,9 @@ endfunction() # Create a python unittest using run_python_tests.sh, # which takes care of making correct running environment function(add_python_test TEST_NAME) - add_test(NAME ${TEST_NAME} - COMMAND bash ${PROJ_ROOT}/paddle/scripts/run_python_tests.sh + add_test(NAME ${TEST_NAME} + COMMAND env PADDLE_PACKAGE_DIR=${PADDLE_PYTHON_PACKAGE_DIR} + bash ${PROJ_ROOT}/paddle/scripts/run_python_tests.sh ${USE_VIRTUALENV_FOR_TEST} ${PYTHON_EXECUTABLE} ${ARGN} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endfunction() diff --git a/paddle/scripts/run_python_tests.sh b/paddle/scripts/run_python_tests.sh index 02d2cdb977..6dfc05a949 100755 --- a/paddle/scripts/run_python_tests.sh +++ b/paddle/scripts/run_python_tests.sh @@ -28,8 +28,13 @@ if [ $USE_VIRTUALENV_FOR_TEST -ne 0 ]; then PYTHON=python fi -export PYTHONPATH=$SCRIPTPATH/../../python/ -$PYTHON -m pip install $SCRIPTPATH/../dist/*.whl requests matplotlib opencv-python ipython==5.3 +$PYTHON -m pip install $SCRIPTPATH/../dist/*.whl + +if [ "X${PADDLE_PACKAGE_DIR}" != "X" ]; then + $PYTHON -m pip install ${PADDLE_PACKAGE_DIR}/*.whl +fi + +$PYTHON -m pip install ipython==5.3 for fn in "$@" do diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index bfa19d5ecc..4f52f0f6cf 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -23,7 +23,9 @@ add_custom_command(OUTPUT ${OUTPUT_DIR}/.timestamp add_custom_target(paddle_python ALL DEPENDS ${OUTPUT_DIR}/.timestamp) +set(PADDLE_PYTHON_PACKAGE_DIR ${CMAKE_CURRENT_BINARY_DIR}/dist/) add_subdirectory(paddle/trainer_config_helpers/tests) + if (WITH_SWIG_PY) # enable v2 API unittest only when paddle swig api is compiled add_subdirectory(paddle/v2/tests) @@ -31,6 +33,6 @@ if (WITH_SWIG_PY) add_subdirectory(paddle/v2/plot/tests) endif() -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/dist/ +install(DIRECTORY ${PADDLE_PYTHON_PACKAGE_DIR} DESTINATION opt/paddle/share/wheels ) diff --git a/python/paddle/v2/plot/tests/CMakeLists.txt b/python/paddle/v2/plot/tests/CMakeLists.txt index b1132f1317..da5cd76488 100644 --- a/python/paddle/v2/plot/tests/CMakeLists.txt +++ b/python/paddle/v2/plot/tests/CMakeLists.txt @@ -1 +1,5 @@ -add_python_test(test_ploter test_ploter.py) +if (NOT APPLE) + # The Mac OS X backend will not be able to function correctly if Python is + # not installed as a framework. + add_python_test(test_ploter test_ploter.py) +endif() diff --git a/python/setup.py.in b/python/setup.py.in index 5dfb46192a..d747288434 100644 --- a/python/setup.py.in +++ b/python/setup.py.in @@ -18,6 +18,7 @@ setup(name='paddle', "numpy", "protobuf==${PROTOBUF_VERSION}", "matplotlib", + "opencv-python" ], packages=packages, package_dir={ From a038163eefd4c9868f15eaeb5be4839c8e990e9d Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Thu, 25 May 2017 13:38:51 +0800 Subject: [PATCH 16/28] Follow comments --- doc/design/parameters_in_cpp.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/design/parameters_in_cpp.md b/doc/design/parameters_in_cpp.md index 4c0dcc1823..b6f99bc7d9 100644 --- a/doc/design/parameters_in_cpp.md +++ b/doc/design/parameters_in_cpp.md @@ -1,4 +1,4 @@ -# Parameters in CPP +# Design Doc: The C++ Class `Parameters` `Parameters` is a concept we designed in Paddle V2 API. `Parameters` is a container of parameters, and make Paddle can shared parameter between topologies. We described usages of `Parameter` in [api.md](./api.md). @@ -33,6 +33,8 @@ The step by step approach for implementation Parameters in Paddle C++ core is li 3. Make `Parameters` support Multi-CPU and Multi-GPU training to prepare for sharing `Parameter` between topologies. Because we need share `Parameters` between topologies, it is `Parameters`'s response to exchange Parameters between GPUs. `GradientMachine` should not handle how to exchange Parameters because `GradientMachine` only used to train one topology and we need to support train many topologies in Paddle, i.e., there could be many GradientMachines use one `Parameters`. + * We should use a global function to exchange Parameters between GPUs, not a member function in `Parameters`. The `MultiGradientMachine` invoke this function, which uses `Parameters` as this function inputs. + * The MultiGradientMachine contains many functionalities. Extracting the Parameters exchanging logic could make MultiGradientMachine clearer and simpler. 4. Make `Parameters` as an argument for `forward/backward` function, not a data member for `GradientMachine`. For example, `forward` could be `forward(const Parameters& params, ...)` and `backward` could be `backward(Parameters* params, ...)`. After this step, Paddle could share `Parameters` between topologies. From ec6068b187c679727246ebbed43468d56e274cb6 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Thu, 25 May 2017 13:45:37 +0800 Subject: [PATCH 17/28] Tinker with TravisCI --- paddle/scripts/run_python_tests.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/paddle/scripts/run_python_tests.sh b/paddle/scripts/run_python_tests.sh index 6dfc05a949..1ed497aaec 100755 --- a/paddle/scripts/run_python_tests.sh +++ b/paddle/scripts/run_python_tests.sh @@ -24,6 +24,8 @@ PYTHON=$1; shift if [ $USE_VIRTUALENV_FOR_TEST -ne 0 ]; then rm -rf .test_env virtualenv .test_env + unset PYTHONHOME + unset PYTHONPATH source .test_env/bin/activate PYTHON=python fi @@ -32,6 +34,8 @@ $PYTHON -m pip install $SCRIPTPATH/../dist/*.whl if [ "X${PADDLE_PACKAGE_DIR}" != "X" ]; then $PYTHON -m pip install ${PADDLE_PACKAGE_DIR}/*.whl +else + export PYTHONPATH=$SCRIPTPATH/../../python/ fi $PYTHON -m pip install ipython==5.3 From 0ee31a03b015a7fe2d5c7eed724ad60a85a5777d Mon Sep 17 00:00:00 2001 From: Luo Tao Date: Thu, 25 May 2017 17:25:26 +0800 Subject: [PATCH 18/28] Expose the "reverse" argument for recurrent_group in V2 API --- python/paddle/v2/layer.py | 14 ++++++++------ python/paddle/v2/tests/test_rnn_layer.py | 5 +++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/python/paddle/v2/layer.py b/python/paddle/v2/layer.py index 3d9caeec58..919c531d18 100644 --- a/python/paddle/v2/layer.py +++ b/python/paddle/v2/layer.py @@ -360,7 +360,7 @@ mixed.__doc__ = conf_helps.mixed_layer.__doc__ class RecurrentLayerInput(Layer): - def __init__(self, recurrent_name, index, parent_layers): + def __init__(self, recurrent_name, index, parent_layers, reverse): parents_len = len(parent_layers) assert parents_len <= 1 if parents_len == 0: @@ -368,6 +368,7 @@ class RecurrentLayerInput(Layer): else: self.__parents__ = parent_layers.values()[0] self.__recurrent_name__ = recurrent_name + self.__reverse__ = reverse name = self.__parents__[ index].name if index >= 0 else self.context_name() super(RecurrentLayerInput, self).__init__( @@ -380,7 +381,8 @@ class RecurrentLayerInput(Layer): model_type('recurrent_nn') RecurrentLayerGroupWithoutOutLinksBegin( name=self.__recurrent_name__, - in_links=map(lambda x: x.name, self.__parents__)) + in_links=map(lambda x: x.name, self.__parents__), + seq_reversed=self.__reverse__) return self @@ -461,7 +463,7 @@ del each_layer_name @wrap_name_default() -def recurrent_group(step, input, name=None): +def recurrent_group(step, input, reverse=False, name=None): if not isinstance(input, collections.Sequence): input = [input] @@ -471,14 +473,14 @@ def recurrent_group(step, input, name=None): RecurrentLayerInput( recurrent_name=name, index=i, - parent_layers={'recurrent_inputs': non_static_inputs}) - for i in xrange(len(non_static_inputs)) + parent_layers={'recurrent_inputs': non_static_inputs}, + reverse=reverse) for i in xrange(len(non_static_inputs)) ] extra_input = None if len(non_static_inputs) == 0: extra_input = RecurrentLayerInput( - recurrent_name=name, index=-1, parent_layers={}) + recurrent_name=name, index=-1, parent_layers={}, reverse=reverse) def __real_step__(*args): rnn_input = list(args) diff --git a/python/paddle/v2/tests/test_rnn_layer.py b/python/paddle/v2/tests/test_rnn_layer.py index 5fbbd20eb7..845277c012 100644 --- a/python/paddle/v2/tests/test_rnn_layer.py +++ b/python/paddle/v2/tests/test_rnn_layer.py @@ -42,7 +42,8 @@ class RNNTest(unittest.TestCase): def test(): data = conf_helps.data_layer(name="word", size=dict_dim) embd = conf_helps.embedding_layer(input=data, size=word_dim) - conf_helps.recurrent_group(name="rnn", step=step, input=embd) + conf_helps.recurrent_group( + name="rnn", step=step, input=embd, reverse=True) return str(parse_network(test)) @@ -60,7 +61,7 @@ class RNNTest(unittest.TestCase): name="word", type=data_type.integer_value(dict_dim)) embd = layer.embedding(input=data, size=word_dim) rnn_layer = layer.recurrent_group( - name="rnn", step=new_step, input=embd) + name="rnn", step=new_step, input=embd, reverse=True) return str(layer.parse_network(rnn_layer)) diff = difflib.unified_diff(parse_old_rnn().splitlines(1), From 7e99af556fca2a7179dc77193754c4b8831b5ac4 Mon Sep 17 00:00:00 2001 From: dangqingqing Date: Thu, 25 May 2017 20:07:30 +0800 Subject: [PATCH 19/28] follow comments --- paddle/py_paddle/dataprovider_converter.py | 42 ++++++++++++---------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/paddle/py_paddle/dataprovider_converter.py b/paddle/py_paddle/dataprovider_converter.py index cfb82e92d5..6234dc65dc 100644 --- a/paddle/py_paddle/dataprovider_converter.py +++ b/paddle/py_paddle/dataprovider_converter.py @@ -60,7 +60,7 @@ class IScanner(object): """ pass - def finish_pre_scan(self, argument, dat=None): + def finish_pre_scan(self, argument): """ Finish first scan pass. Allocate the memory. @@ -103,23 +103,29 @@ class DenseScanner(IScanner): def pre_scan(self, dat): self.__height__ += 1 + if self.__shape__ is None: + self.__shape__ = numpy.array(dat).shape + if len(self.__shape__) > 3: + raise ValueError( + "The dimension of input cannot be greater than 3.") + else: + if self.__shape__ != numpy.array(dat).shape: + raise ValueError( + "The data shape must be same in one mini-batch.") - def finish_pre_scan(self, argument, dat=None): - self.__shape__ = numpy.array(dat).shape - if len(self.__shape__) > 3: - raise ValueError("The dimension of input is greater than 3.") + def finish_pre_scan(self, argument): dim = reduce(lambda x, y: x * y, self.__shape__) - if len(self.__shape__) == 1: - assert dim == self.input_type.dim + if len(self.__shape__) == 1 and dim != self.input_type.dim: + raise ValueError("The data size must be equal to it in data layer.") self.__mat__ = numpy.ndarray( shape=(self.__height__, dim), dtype=numpy.float32) self.__height__ = 0 def scan(self, dat): - if isinstance(dat, numpy.ndarray): - assert self.__shape__ == dat.shape - dat = dat.flatten() - self.__mat__[self.__height__] = dat + # It's better to use NumPy array for speed. + d = numpy.array(dat) + d = d.flatten() + self.__mat__[self.__height__] = d self.__height__ += 1 def finish_scan(self, argument): @@ -136,6 +142,7 @@ class DenseScanner(IScanner): h, w = self.__shape__[-2:] argument.setSlotFrameHeight(self.pos, h) argument.setSlotFrameWidth(self.pos, w) + self.__shape__ = None class SparseBinaryScanner(IScanner): @@ -186,7 +193,7 @@ class IndexScanner(IScanner): def pre_scan(self, dat): self.__idx__ += 1 - def finish_pre_scan(self, argument, dat=None): + def finish_pre_scan(self, argument): self.__ids__ = [0] * self.__idx__ self.__idx__ = 0 @@ -211,8 +218,8 @@ class SequenceScanner(IScanner): for each in dat: self.__inner_scanner__.pre_scan(each) - def finish_pre_scan(self, argument, dat=None): - self.__inner_scanner__.finish_pre_scan(argument, dat) + def finish_pre_scan(self, argument): + self.__inner_scanner__.finish_pre_scan(argument) def scan(self, dat): self.__seq__.append(self.__seq__[-1] + self.get_size(dat)) @@ -253,11 +260,8 @@ class DataProviderConverter(object): for each_step, scanner in itertools.izip(each_sample, scanners): scanner.pre_scan(each_step) - # Some scanners, like dense scanner, pre-allocate memory for mini-batch - # in finish_pre_scan function. The dat[0] is used to calculate the size - # of input data. - for scanner, each_feature in itertools.izip(scanners, dat[0]): - scanner.finish_pre_scan(argument, each_feature) + for scanner in scanners: + scanner.finish_pre_scan(argument) for each_sample in dat: for each_step, scanner in itertools.izip(each_sample, scanners): From 8e06f7314a5b18ae0a28687e9fb05b4f417fca20 Mon Sep 17 00:00:00 2001 From: dangqingqing Date: Thu, 25 May 2017 20:15:04 +0800 Subject: [PATCH 20/28] refine code --- paddle/py_paddle/dataprovider_converter.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/paddle/py_paddle/dataprovider_converter.py b/paddle/py_paddle/dataprovider_converter.py index 6234dc65dc..edc2e02923 100644 --- a/paddle/py_paddle/dataprovider_converter.py +++ b/paddle/py_paddle/dataprovider_converter.py @@ -100,6 +100,7 @@ class DenseScanner(IScanner): self.__mat__ = None self.__shape__ = None self.__height__ = 0 + self.__dim__ = 0 def pre_scan(self, dat): self.__height__ += 1 @@ -108,24 +109,25 @@ class DenseScanner(IScanner): if len(self.__shape__) > 3: raise ValueError( "The dimension of input cannot be greater than 3.") + self.__dim__ = reduce(lambda x, y: x * y, self.__shape__) + if len(self.__shape__) == 1 and self.__dim__ != self.input_type.dim: + raise ValueError( + "The data size must be equal to it in data layer.") else: if self.__shape__ != numpy.array(dat).shape: raise ValueError( "The data shape must be same in one mini-batch.") def finish_pre_scan(self, argument): - dim = reduce(lambda x, y: x * y, self.__shape__) - if len(self.__shape__) == 1 and dim != self.input_type.dim: - raise ValueError("The data size must be equal to it in data layer.") self.__mat__ = numpy.ndarray( - shape=(self.__height__, dim), dtype=numpy.float32) + shape=(self.__height__, self.__dim__), dtype=numpy.float32) self.__height__ = 0 def scan(self, dat): # It's better to use NumPy array for speed. - d = numpy.array(dat) - d = d.flatten() - self.__mat__[self.__height__] = d + dat = numpy.array(dat) + dat = dat.flatten() + self.__mat__[self.__height__] = dat self.__height__ += 1 def finish_scan(self, argument): From 35bfb1d5c3d516314dbc436ea4e557eae47be81c Mon Sep 17 00:00:00 2001 From: xuwei06 Date: Thu, 25 May 2017 10:26:32 -0700 Subject: [PATCH 21/28] Allow setting both is_static and initial_mean, initial_std at the same time. Some time we simply want to have a fixed initialization for a model. --- python/paddle/trainer_config_helpers/attrs.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/python/paddle/trainer_config_helpers/attrs.py b/python/paddle/trainer_config_helpers/attrs.py index 7ae9e5cb30..d1167a234c 100644 --- a/python/paddle/trainer_config_helpers/attrs.py +++ b/python/paddle/trainer_config_helpers/attrs.py @@ -110,15 +110,16 @@ class ParameterAttribute(object): momentum=None, gradient_clipping_threshold=None, sparse_update=False): - # initialize strategy. + self.attr = {} + if is_static: - self.attr = {'is_static': True} - elif initial_std is None and initial_mean is None and initial_max \ + self.attr['is_static'] = True + + if initial_std is None and initial_mean is None and initial_max \ is None and initial_min is None: - self.attr = {'initial_smart': True} + self.attr['initial_smart'] = True elif is_compatible_with(initial_std, float) or \ is_compatible_with(initial_mean, float): - self.attr = dict() if initial_std is not None: self.attr['initial_std'] = initial_std if initial_mean is not None: @@ -131,7 +132,6 @@ class ParameterAttribute(object): assert initial_min < initial_max initial_mean = (initial_max + initial_min) / 2 initial_std = initial_mean - initial_min - self.attr = dict() self.attr['initial_mean'] = initial_mean self.attr['initial_std'] = initial_std self.attr['initial_strategy'] = 1 # Uniform Random From bf358be479523f0f7848ece557054835d21d30ed Mon Sep 17 00:00:00 2001 From: Helin Wang Date: Thu, 25 May 2017 12:06:48 -0700 Subject: [PATCH 22/28] update design doc: Client Library of Parameter Server --- doc/design/cluster_train/pserver_client.md | 12 +++++------- .../cluster_train/src/pserver_init.graffle | Bin 2622 -> 2436 bytes doc/design/cluster_train/src/pserver_init.png | Bin 28853 -> 28616 bytes 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/doc/design/cluster_train/pserver_client.md b/doc/design/cluster_train/pserver_client.md index 392bab25e9..007285640e 100644 --- a/doc/design/cluster_train/pserver_client.md +++ b/doc/design/cluster_train/pserver_client.md @@ -55,7 +55,7 @@ The trainer select process is encapsulated in the C API function: ```c int paddle_begin_init_params(paddle_pserver_client* client, const char* config_proto); ``` -The selected trainer's call to `paddle_begin_init_params` will return with 1, and the other trainers' call to `paddle_begin_init_params` will block until initialization is done, and return 0. As illustrated below: +The selected trainer's call to `paddle_begin_init_params` will return with 1, and the other trainers' call to `paddle_begin_init_params` will return 0. `paddle_get_params` will be blocked until initialization is completed. As illustrated below: @@ -89,16 +89,13 @@ void paddle_pserver_client_release(paddle_pserver_client* client); * * paddle_begin_init_params will be called from multiple trainers, * only one trainer will be selected to initialize the parameters on - * parameter servers. Other trainers will be blocked until the - * initialization is done, and they need to get the initialized + * parameter servers. Other trainers need to get the initialized * parameters from parameter servers using @paddle_get_params. * - * @param pserver_config_proto serialized parameter server configuration in - * Protocol Buffers format. * @return 1 if the trainer is selected to initialize parameter * servers, otherwise 0. */ -int paddle_begin_init_params(paddle_pserver_client* client, const char* pserver_config_proto); +int paddle_begin_init_params(paddle_pserver_client* client); /** * @brief paddle_init_param initializes the parameter on parameter @@ -106,12 +103,13 @@ int paddle_begin_init_params(paddle_pserver_client* client, const char* pserver_ * * @param param the parameter to initialize. * @param param_config_proto the configuration for the parameter. + * @param config_len the length of param_config_proto * @return 0 if successful, otherwise -1. On failure, the trainer * needs to restart the entire initialization process (starting from * @paddle_begin_init_param). Or simply exit the program and wait for * the cluster management system to restart the trainer. */ -int paddle_init_param(paddle_pserver_client* client, paddle_parameter params, const char* param_config_proto); +int paddle_init_param(paddle_pserver_client* client, paddle_parameter param, const unsigned char* param_config_proto, int config_len); /** * @brief paddle_finish_init_params tells parameter servers client has diff --git a/doc/design/cluster_train/src/pserver_init.graffle b/doc/design/cluster_train/src/pserver_init.graffle index 730d3a561ffdc19e723b3cf6612471440951826a..5f3f1f52be8aa7f9049a8fcd6b7c93c8560c1676 100644 GIT binary patch literal 2436 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 T<)yoy*OQS@cvT{1=>I4S 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 Date: Tue, 23 May 2017 21:56:51 -0400 Subject: [PATCH 23/28] implement task handling for master server's service --- doc/design/cluster_train/master_server.md | 16 +- paddle/go/master/service.go | 179 ++++++++++++++++++++++ paddle/go/master/service_internal_test.go | 32 ++++ 3 files changed, 219 insertions(+), 8 deletions(-) create mode 100644 paddle/go/master/service.go create mode 100644 paddle/go/master/service_internal_test.go diff --git a/doc/design/cluster_train/master_server.md b/doc/design/cluster_train/master_server.md index bb83076525..4bf3c506f1 100644 --- a/doc/design/cluster_train/master_server.md +++ b/doc/design/cluster_train/master_server.md @@ -10,7 +10,7 @@ A dataset is a list of files in *RecordIO* format. A RecordIO file consists of c ## Task Queue -As mentioned in [distributed training design doc](./README.md), a *task* is a data shard that the master server assigns to the trainer process to train on. A task consists of one or multiple *blocks* from one or multiple files. The master server maintains *task queues* to track the training progress. +As mentioned in [distributed training design doc](./README.md), a *task* is a data shard that the master server assigns to the trainer process to train on. A task consists of one or multiple *chunks* from one or multiple files. The master server maintains *task queues* to track the training progress. ### Task Queue Creation @@ -21,23 +21,23 @@ As mentioned in [distributed training design doc](./README.md), a *task* is a da func (m *RPCServer) ReportDataset(Paths []string, dummy *int) error { } ``` -1. The master server will scan through each RecordIO file to generate the *block index* and know how many blocks does each file have. A block can be referenced by the file path and the index of the block within the file. The block index is in memory data structure that enables fast access to each block, and the index of the block with the file is an integer start from 0, representing the n-th block within the file. +1. The master server will scan through each RecordIO file to generate the *chunk index* and know how many chunks does each file have. A chunk can be referenced by the file path and the index of the chunk within the file. The chunk index is in memory data structure that enables fast access to each chunk, and the index of the chunk with the file is an integer start from 0, representing the n-th chunk within the file. - The definition of the block is: + The definition of the chunk is: ```go - type Block struct { - Idx int // index of the block within the file + type Chunk struct { + Idx int // index of the chunk within the file Path string - Index recordio.Index // block index + Index recordio.Index // chunk index } ``` -1. Blocks are grouped into tasks, and tasks are filled into the todo queue. The pending queue and the done queue are initialized with no element. +1. Chunks are grouped into tasks, and tasks are filled into the todo queue. The pending queue and the done queue are initialized with no element. The definition of the task is: ```go type Task struct { Index int - Blocks []Block + Chunks []Chunk } ``` diff --git a/paddle/go/master/service.go b/paddle/go/master/service.go new file mode 100644 index 0000000000..ae7f9687a5 --- /dev/null +++ b/paddle/go/master/service.go @@ -0,0 +1,179 @@ +package master + +import ( + "errors" + "log" + "sync" + "time" + + "github.com/wangkuiyi/recordio" +) + +const ( + targetTaskCount = 300 +) + +// errors +var ( + ErrNoMoreTask = errors.New("no more task for current pass") + ErrPendingTaskNotFound = errors.New("pending task not found") +) + +// Service is the master server service. +type Service struct { + timeoutDur time.Duration + timeoutMax int + + mu sync.Mutex + taskQueues taskQueues +} + +// Recover recovers service state from etcd. +func Recover() (*Service, error) { + // TODO(helin): recover from snapshot state from etcd. + return nil, nil +} + +func partition(chunks []Chunk, targetTaskCount int) []taskEntry { + id := 0 + chunkPerTask := len(chunks) / targetTaskCount + if chunkPerTask <= 0 { + chunkPerTask = 1 + } + + var result []taskEntry + var cur taskEntry + for i, c := range chunks { + if i%chunkPerTask == 0 && len(cur.Task.Chunks) > 0 { + cur.Task.ID = id + id++ + result = append(result, cur) + cur.Task.Chunks = nil + } + + cur.Task.Chunks = append(cur.Task.Chunks, c) + } + + if len(cur.Task.Chunks) > 0 { + cur.Task.ID = id + id++ + result = append(result, cur) + } + + return result +} + +// NewService creates a new service. +func NewService(chunks []Chunk, timeoutDur time.Duration, timeoutMax int) (*Service, error) { + s := &Service{} + s.timeoutDur = timeoutDur + s.timeoutMax = timeoutMax + s.taskQueues = taskQueues{} + s.taskQueues.Pending = make(map[int]taskEntry) + s.taskQueues.Todo = partition(chunks, targetTaskCount) + return s, nil +} + +// Chunk is a chunk of data consisted of several data instances. +type Chunk struct { + Idx int // index of the chunk within the file + Path string + Index recordio.Index // block index +} + +// Task is the basic unit of data instances assigned to trainers. +type Task struct { + ID int + Chunks []Chunk +} + +type taskEntry struct { + Epoch int + NumTimeout int + Task Task +} + +type taskQueues struct { + Todo []taskEntry + Pending map[int]taskEntry // map from task ID to task entry + Done []taskEntry + Failed []Task +} + +// *must* be called with s.mu being held. +func (s *Service) snapshot() error { + // TODO(helin): snapshot state on etcd. + return nil +} + +// GetTask gets a new task from the service. +func (s *Service) GetTask(dummy int, task *Task) error { + s.mu.Lock() + defer s.mu.Unlock() + + if len(s.taskQueues.Todo) == 0 { + return ErrNoMoreTask + } + + t := s.taskQueues.Todo[0] + t.Epoch++ + s.taskQueues.Todo = s.taskQueues.Todo[1:] + s.taskQueues.Pending[t.Task.ID] = t + err := s.snapshot() + if err != nil { + return err + } + + time.AfterFunc(s.timeoutDur, func(taskID int, epoch int) func() { + return func() { + s.mu.Lock() + defer s.mu.Unlock() + + t, ok := s.taskQueues.Pending[taskID] + if !ok { + return + } + + if t.Epoch != epoch { + // new epoch, task launched after the + // schedule of this timeout check. + return + } + + defer func() { + err := s.snapshot() + if err != nil { + log.Println(err) + } + }() + + delete(s.taskQueues.Pending, t.Task.ID) + + t.NumTimeout++ + if t.NumTimeout > s.timeoutMax { + s.taskQueues.Failed = append(s.taskQueues.Failed, t.Task) + return + } + + s.taskQueues.Todo = append(s.taskQueues.Todo, t) + } + }(t.Task.ID, t.Epoch)) + return nil +} + +// TaskFinished tell the service that a task is finished. +func (s *Service) TaskFinished(taskID int, dummy *int) error { + s.mu.Lock() + defer s.mu.Unlock() + + t, ok := s.taskQueues.Pending[taskID] + if !ok { + return ErrPendingTaskNotFound + } + + // task finished, reset timeout + t.NumTimeout = 0 + s.taskQueues.Done = append(s.taskQueues.Done, t) + delete(s.taskQueues.Pending, taskID) + return s.snapshot() +} diff --git a/paddle/go/master/service_internal_test.go b/paddle/go/master/service_internal_test.go new file mode 100644 index 0000000000..1e6197d241 --- /dev/null +++ b/paddle/go/master/service_internal_test.go @@ -0,0 +1,32 @@ +package master + +import "testing" + +func TestPartitionCount(t *testing.T) { + cs := make([]Chunk, 100) + ts := partition(cs, 20) + if len(ts) != 20 { + t.Error(len(ts)) + } + + cs = make([]Chunk, 101) + ts = partition(cs, 20) + if len(ts) != 21 { + t.Error(len(ts)) + } + + ts = partition(cs, 200) + if len(ts) != 101 { + t.Error(len(ts)) + } +} + +func TestPartionIndex(t *testing.T) { + cs := make([]Chunk, 100) + ts := partition(cs, 20) + for i := range ts { + if ts[i].Task.ID != i { + t.Error(ts[i], i) + } + } +} From 025e7f9cb6c4865f18f66d4c6a19b60ddbea3da2 Mon Sep 17 00:00:00 2001 From: Helin Wang Date: Wed, 24 May 2017 20:08:55 -0400 Subject: [PATCH 24/28] implement basic master server --- paddle/go/cmd/master/master.go | 78 ++++++++++++++++++++++++++++++++++ paddle/go/master/service.go | 4 +- 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 paddle/go/cmd/master/master.go diff --git a/paddle/go/cmd/master/master.go b/paddle/go/cmd/master/master.go new file mode 100644 index 0000000000..8346b42a32 --- /dev/null +++ b/paddle/go/cmd/master/master.go @@ -0,0 +1,78 @@ +package main + +import ( + "flag" + "net" + "net/http" + "net/rpc" + "os" + "strconv" + "strings" + "time" + + "github.com/PaddlePaddle/Paddle/paddle/go/master" + "github.com/wangkuiyi/recordio" +) + +const ( + taskTimeoutDur = 20 * time.Minute + taskTimeoutMax = 3 +) + +func main() { + port := flag.Int("p", 0, "port of the master server") + dataset := flag.String("d", "", "dataset: comma separated path to RecordIO files") + faultTolerant := flag.Bool("fault-tolerance", false, "enable fault tolerance (requires etcd).") + flag.Parse() + + if *dataset == "" { + panic("no dataset specified.") + } + + if *faultTolerant { + panic("fault tolernat not implemented.") + } + + var chunks []master.Chunk + paths := strings.Split(*dataset, ",") + idx := 0 + for _, path := range paths { + f, err := os.Open(path) + if err != nil { + panic(err) + } + + index, err := recordio.LoadIndex(f) + if err != nil { + panic(err) + } + f.Close() + + count := index.NumChunks() + for i := 0; i < count; i++ { + chunk := master.Chunk{ + Idx: idx, + Path: path, + Index: *index.ChunkIndex(i), + } + chunks = append(chunks, chunk) + } + } + + s := master.NewService(chunks, taskTimeoutDur, taskTimeoutMax) + err := rpc.Register(s) + if err != nil { + panic(err) + } + + rpc.HandleHTTP() + l, err := net.Listen("tcp", ":"+strconv.Itoa(*port)) + if err != nil { + panic(err) + } + + err = http.Serve(l, nil) + if err != nil { + panic(err) + } +} diff --git a/paddle/go/master/service.go b/paddle/go/master/service.go index ae7f9687a5..652d345e01 100644 --- a/paddle/go/master/service.go +++ b/paddle/go/master/service.go @@ -64,14 +64,14 @@ func partition(chunks []Chunk, targetTaskCount int) []taskEntry { } // NewService creates a new service. -func NewService(chunks []Chunk, timeoutDur time.Duration, timeoutMax int) (*Service, error) { +func NewService(chunks []Chunk, timeoutDur time.Duration, timeoutMax int) *Service { s := &Service{} s.timeoutDur = timeoutDur s.timeoutMax = timeoutMax s.taskQueues = taskQueues{} s.taskQueues.Pending = make(map[int]taskEntry) s.taskQueues.Todo = partition(chunks, targetTaskCount) - return s, nil + return s } // Chunk is a chunk of data consisted of several data instances. From 6ce7c8bc873b73a7cd7a5cdb1d0b861d8d3ef23a Mon Sep 17 00:00:00 2001 From: Helin Wang Date: Thu, 25 May 2017 16:05:29 -0400 Subject: [PATCH 25/28] update recordIO include path --- paddle/go/cmd/master/master.go | 2 +- paddle/go/master/service.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/paddle/go/cmd/master/master.go b/paddle/go/cmd/master/master.go index 8346b42a32..16052fd75c 100644 --- a/paddle/go/cmd/master/master.go +++ b/paddle/go/cmd/master/master.go @@ -11,7 +11,7 @@ import ( "time" "github.com/PaddlePaddle/Paddle/paddle/go/master" - "github.com/wangkuiyi/recordio" + "github.com/PaddlePaddle/Paddle/paddle/go/recordio" ) const ( diff --git a/paddle/go/master/service.go b/paddle/go/master/service.go index 652d345e01..cf15f28cc7 100644 --- a/paddle/go/master/service.go +++ b/paddle/go/master/service.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/wangkuiyi/recordio" + "github.com/PaddlePaddle/Paddle/paddle/go/recordio" ) const ( From 9b11e17d8d38e83c25be358193bb66b778cbc31c Mon Sep 17 00:00:00 2001 From: Helin Wang Date: Thu, 25 May 2017 17:11:29 -0400 Subject: [PATCH 26/28] fix according to comments --- paddle/go/cmd/master/master.go | 41 ++++++++++++++++------- paddle/go/cmd/pserver/pserver.go | 5 +-- paddle/go/master/service.go | 13 ++++--- paddle/go/master/service_internal_test.go | 11 ++++-- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/paddle/go/cmd/master/master.go b/paddle/go/cmd/master/master.go index 16052fd75c..ef1f87c2dd 100644 --- a/paddle/go/cmd/master/master.go +++ b/paddle/go/cmd/master/master.go @@ -1,40 +1,55 @@ package main import ( - "flag" + "fmt" "net" "net/http" "net/rpc" "os" + "path/filepath" "strconv" "strings" "time" + "github.com/namsral/flag" + "github.com/PaddlePaddle/Paddle/paddle/go/master" "github.com/PaddlePaddle/Paddle/paddle/go/recordio" ) -const ( - taskTimeoutDur = 20 * time.Minute - taskTimeoutMax = 3 -) - func main() { - port := flag.Int("p", 0, "port of the master server") - dataset := flag.String("d", "", "dataset: comma separated path to RecordIO files") - faultTolerant := flag.Bool("fault-tolerance", false, "enable fault tolerance (requires etcd).") + port := flag.Int("port", 8080, "port of the master server.") + dataset := flag.String("training_dataset", "", "dataset: comma separated path to RecordIO paths, supports golb patterns.") + faultTolerance := flag.Bool("fault_tolerance", false, "enable fault tolerance (requires etcd).") + taskTimeoutDur := flag.Duration("task_timout_dur", 20*time.Minute, "task timout duration.") + taskTimeoutMax := flag.Int("task_timeout_max", 3, "max timtout count for each task before it being declared failed task.") + chunkPerTask := flag.Int("chunk_per_task", 10, "chunk per task.") flag.Parse() if *dataset == "" { panic("no dataset specified.") } - if *faultTolerant { - panic("fault tolernat not implemented.") + if *faultTolerance { + panic("fault tolernance not implemented.") } var chunks []master.Chunk - paths := strings.Split(*dataset, ",") + var paths []string + ss := strings.Split(*dataset, ",") + fmt.Println(ss) + for _, s := range ss { + match, err := filepath.Glob(s) + if err != nil { + panic(err) + } + paths = append(paths, match...) + } + + if len(paths) == 0 { + panic("no valid datset specified.") + } + idx := 0 for _, path := range paths { f, err := os.Open(path) @@ -59,7 +74,7 @@ func main() { } } - s := master.NewService(chunks, taskTimeoutDur, taskTimeoutMax) + s := master.NewService(chunks, *chunkPerTask, *taskTimeoutDur, *taskTimeoutMax) err := rpc.Register(s) if err != nil { panic(err) diff --git a/paddle/go/cmd/pserver/pserver.go b/paddle/go/cmd/pserver/pserver.go index 41417875fb..bd4bfc7028 100644 --- a/paddle/go/cmd/pserver/pserver.go +++ b/paddle/go/cmd/pserver/pserver.go @@ -1,17 +1,18 @@ package main import ( - "flag" "net" "net/http" "net/rpc" "strconv" + "github.com/namsral/flag" + "github.com/PaddlePaddle/Paddle/paddle/go/pserver" ) func main() { - port := flag.Int("p", 0, "port of the pserver") + port := flag.Int("port", 0, "port of the pserver") flag.Parse() s := pserver.NewService() diff --git a/paddle/go/master/service.go b/paddle/go/master/service.go index cf15f28cc7..7526648287 100644 --- a/paddle/go/master/service.go +++ b/paddle/go/master/service.go @@ -34,17 +34,16 @@ func Recover() (*Service, error) { return nil, nil } -func partition(chunks []Chunk, targetTaskCount int) []taskEntry { +func partition(chunks []Chunk, chunksPerTask int) []taskEntry { id := 0 - chunkPerTask := len(chunks) / targetTaskCount - if chunkPerTask <= 0 { - chunkPerTask = 1 + if chunksPerTask <= 0 { + chunksPerTask = 1 } var result []taskEntry var cur taskEntry for i, c := range chunks { - if i%chunkPerTask == 0 && len(cur.Task.Chunks) > 0 { + if i%chunksPerTask == 0 && len(cur.Task.Chunks) > 0 { cur.Task.ID = id id++ result = append(result, cur) @@ -64,13 +63,13 @@ func partition(chunks []Chunk, targetTaskCount int) []taskEntry { } // NewService creates a new service. -func NewService(chunks []Chunk, timeoutDur time.Duration, timeoutMax int) *Service { +func NewService(chunks []Chunk, chunksPerTask int, timeoutDur time.Duration, timeoutMax int) *Service { s := &Service{} s.timeoutDur = timeoutDur s.timeoutMax = timeoutMax s.taskQueues = taskQueues{} s.taskQueues.Pending = make(map[int]taskEntry) - s.taskQueues.Todo = partition(chunks, targetTaskCount) + s.taskQueues.Todo = partition(chunks, chunksPerTask) return s } diff --git a/paddle/go/master/service_internal_test.go b/paddle/go/master/service_internal_test.go index 1e6197d241..bc435b505c 100644 --- a/paddle/go/master/service_internal_test.go +++ b/paddle/go/master/service_internal_test.go @@ -4,18 +4,23 @@ import "testing" func TestPartitionCount(t *testing.T) { cs := make([]Chunk, 100) - ts := partition(cs, 20) + ts := partition(cs, 5) if len(ts) != 20 { t.Error(len(ts)) } cs = make([]Chunk, 101) - ts = partition(cs, 20) + ts = partition(cs, 5) if len(ts) != 21 { t.Error(len(ts)) } - ts = partition(cs, 200) + ts = partition(cs, 1) + if len(ts) != 101 { + t.Error(len(ts)) + } + + ts = partition(cs, 0) if len(ts) != 101 { t.Error(len(ts)) } From 9068da12202f402525dc129dde28520a2e522fb0 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Fri, 26 May 2017 11:45:52 +0800 Subject: [PATCH 27/28] Add user can define PROTOBUF_ROOT. --- .gitignore | 2 ++ cmake/external/protobuf.cmake | 26 +++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 2b30f7938c..9ed10d92d8 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ third_party/ *~ bazel-* third_party/ +# for clion +cmake-build-* diff --git a/cmake/external/protobuf.cmake b/cmake/external/protobuf.cmake index b35e6839cd..831118b03a 100644 --- a/cmake/external/protobuf.cmake +++ b/cmake/external/protobuf.cmake @@ -14,6 +14,28 @@ INCLUDE(ExternalProject) +macro(PROMPT_PROTOBUF_LIB) + MESSAGE(STATUS "Protobuf protoc executable: ${PROTOBUF_PROTOC_EXECUTABLE}") + MESSAGE(STATUS "Protobuf library: ${PROTOBUF_LIBRARY}") + INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR}) + RETURN() +endmacro() + +set(PROTOBUF_ROOT "" CACHE PATH "Folder contains protobuf") +if (NOT "${PROTOBUF_ROOT}" STREQUAL "") + find_path(PROTOBUF_INCLUDE_DIR google/protobuf/message.h PATHS ${PROTOBUF_ROOT}/include) + find_library(PROTOBUF_LIBRARY protobuf PATHS ${PROTOBUF_ROOT}/lib) + find_library(PROTOBUF_LITE_LIBRARY protobuf-lite PATHS ${PROTOBUF_ROOT}/lib) + find_library(PROTOBUF_PROTOC_LIBRARY protoc PATHS ${PROTOBUF_ROOT}/lib) + find_program(PROTOBUF_PROTOC_EXECUTABLE protoc PATHS ${PROTOBUF_ROOT}/bin) + if (PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY AND PROTOBUF_LITE_LIBRARY AND PROTOBUF_PROTOC_LIBRARY) + message(STATUS "Using custom protobuf library in ${PROTOBUF_ROOT}.") + PROMPT_PROTOBUF_LIB() + else() + message(WARNING "Cannot find protobuf library in ${PROTOBUF_ROOT}.") + endif() +endif() + FUNCTION(build_protobuf TARGET_NAME BUILD_FOR_HOST) SET(PROTOBUF_SOURCES_DIR ${THIRD_PARTY_PATH}/${TARGET_NAME}) SET(PROTOBUF_INSTALL_DIR ${THIRD_PARTY_PATH}/install/${TARGET_NAME}) @@ -107,6 +129,4 @@ IF(NOT PROTOBUF_FOUND) SET(PROTOBUF_PROTOC_LIBRARY ${protobuf_PROTOC_LIBRARY} CACHE FILEPATH "protoc library." FORCE) ENDIF(NOT PROTOBUF_FOUND) -MESSAGE(STATUS "Protobuf protoc executable: ${PROTOBUF_PROTOC_EXECUTABLE}") -MESSAGE(STATUS "Protobuf library: ${PROTOBUF_LIBRARY}") -INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR}) +PROMPT_PROTOBUF_LIB() \ No newline at end of file From f6cf9fa8393ccd9829629a82d6fafd830b85da93 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Fri, 26 May 2017 12:38:22 +0800 Subject: [PATCH 28/28] Add missing condition in if --- cmake/external/protobuf.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/external/protobuf.cmake b/cmake/external/protobuf.cmake index 831118b03a..da46eaff50 100644 --- a/cmake/external/protobuf.cmake +++ b/cmake/external/protobuf.cmake @@ -28,7 +28,7 @@ if (NOT "${PROTOBUF_ROOT}" STREQUAL "") find_library(PROTOBUF_LITE_LIBRARY protobuf-lite PATHS ${PROTOBUF_ROOT}/lib) find_library(PROTOBUF_PROTOC_LIBRARY protoc PATHS ${PROTOBUF_ROOT}/lib) find_program(PROTOBUF_PROTOC_EXECUTABLE protoc PATHS ${PROTOBUF_ROOT}/bin) - if (PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY AND PROTOBUF_LITE_LIBRARY AND PROTOBUF_PROTOC_LIBRARY) + if (PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY AND PROTOBUF_LITE_LIBRARY AND PROTOBUF_PROTOC_LIBRARY AND PROTOBUF_PROTOC_EXECUTABLE) message(STATUS "Using custom protobuf library in ${PROTOBUF_ROOT}.") PROMPT_PROTOBUF_LIB() else()