Skip to content

Commit a9dbdab

Browse files
authored
Merge pull request #7396 from reyoung/feature/parallel_for_unittest
Feature/parallel for unittest
2 parents 95c0c12 + 83c7253 commit a9dbdab

File tree

2 files changed

+155
-41
lines changed

2 files changed

+155
-41
lines changed

paddle/framework/init.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ distributed under the License is distributed on an "AS IS" BASIS,
1111
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
See the License for the specific language governing permissions and
1313
limitations under the License. */
14+
#include <string.h> // for strdup
1415
#include <algorithm>
1516
#include <string>
1617

@@ -60,7 +61,9 @@ void InitDevices() {
6061
}
6162

6263
void InitGLOG(const std::string &prog_name) {
63-
google::InitGoogleLogging(prog_name.c_str());
64+
// glog will not hold the ARGV[0] inside.
65+
// Use strdup to alloc a new string.
66+
google::InitGoogleLogging(strdup(prog_name.c_str()));
6467
google::InstallFailureSignalHandler();
6568
}
6669

python/paddle/v2/fluid/tests/test_parallel_op.py

Lines changed: 151 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,156 @@
11
import unittest
2-
3-
import paddle.v2.fluid.layers as layers
42
import paddle.v2.fluid as fluid
5-
from paddle.v2.fluid.framework import Program
6-
from paddle.v2.fluid.executor import Executor
7-
from paddle.v2.fluid.backward import append_backward
8-
import numpy as np
9-
import paddle.v2.fluid.core as core
10-
11-
12-
class ParallelOpTest(unittest.TestCase):
13-
def setUp(self):
14-
x = layers.data(
15-
shape=[-1, 30, 40],
16-
dtype='float32',
17-
name='x',
18-
append_batch_size=False,
19-
stop_gradient=False)
20-
21-
places = layers.get_places(device_count=4)
22-
pd = layers.ParallelDo(places=places)
23-
24-
with pd.do():
25-
data = pd.read_input(x)
26-
hidden = layers.fc(input=data, size=7)
27-
pd.write_output(hidden)
28-
data = pd()
29-
loss = layers.mean(x=data)
30-
sgd_optimizer = fluid.optimizer.SGD(learning_rate=0.001)
31-
sgd_optimizer.minimize(loss)
32-
33-
exe = fluid.Executor(fluid.CPUPlace())
34-
exe.run(fluid.default_startup_program())
35-
exe.run(fluid.default_main_program(),
36-
feed={
37-
x.name: np.random.uniform(0.1, 0.6,
38-
(20, 30, 40)).astype("float32")
39-
})
40-
41-
def test_forward(self):
42-
pass
3+
import numpy
4+
5+
6+
class BaseParallelForTest(unittest.TestCase):
7+
def run_test(self, callback, feed, fetch):
8+
"""
9+
Run the unittest for parallel.for
10+
Args:
11+
callback(callable): A callable function returns a generator. There
12+
are two yields in the generator function. The first yield
13+
returns the data layers, and the second yield returns the loss.
14+
The modified data variables will be sent back during the first
15+
yield.
16+
17+
feed(dict): The executor feeding dictionary.
18+
fetch(list|basestr): The fetch name lists.
19+
20+
Returns:
21+
None
22+
23+
Raises:
24+
AssertionError when the computation of cpu, parallel.for in cpu,
25+
gpu, parallel.for in gpu are different.
26+
27+
"""
28+
cpu = fluid.CPUPlace()
29+
result_cpu = self._run_test_impl_(
30+
callback=callback,
31+
feed=feed,
32+
fetch=fetch,
33+
place=cpu,
34+
use_parallel=False)
35+
result_cpu_parallel = self._run_test_impl_(
36+
callback=callback,
37+
feed=feed,
38+
fetch=fetch,
39+
place=cpu,
40+
use_parallel=True)
41+
if fluid.core.is_compile_gpu():
42+
gpu = fluid.CUDAPlace(0)
43+
result_gpu = self._run_test_impl_(
44+
callback=callback,
45+
feed=feed,
46+
fetch=fetch,
47+
place=gpu,
48+
use_parallel=False)
49+
result_gpu_parallel = self._run_test_impl_(
50+
callback=callback,
51+
feed=feed,
52+
fetch=fetch,
53+
place=gpu,
54+
use_parallel=True)
55+
self._assert_same_(fetch, result_cpu, result_cpu_parallel,
56+
result_gpu, result_gpu_parallel)
57+
else:
58+
self._assert_same_(fetch, result_cpu, result_cpu_parallel)
59+
60+
def _run_test_impl_(self, callback, feed, fetch, place, use_parallel=False):
61+
"""
62+
Run a single test, returns the fetch values
63+
Args:
64+
place(Place): the computation place.
65+
use_parallel(bool): Whether use parallel.for or not.
66+
67+
Returns:
68+
Fetched numpy arrays.
69+
70+
"""
71+
if isinstance(fetch, basestring):
72+
fetch = [fetch]
73+
main = fluid.Program()
74+
startup = fluid.Program()
75+
# Fix seed
76+
main.random_seed = 10
77+
startup.random_seed = 10
78+
79+
with fluid.program_guard(main, startup):
80+
generator = callback()
81+
# Automatically insert parallel do if use_parallel = True
82+
if use_parallel:
83+
places = fluid.layers.get_places()
84+
pd = fluid.layers.ParallelDo(places)
85+
data = next(generator)
86+
87+
if isinstance(data, fluid.Variable):
88+
data = [data]
89+
90+
with pd.do():
91+
ins = map(pd.read_input, data)
92+
if len(ins) == 1:
93+
ins = ins[0]
94+
loss = generator.send(ins) # patch input
95+
pd.write_output(loss)
96+
97+
loss = pd()
98+
else:
99+
data = next(generator)
100+
loss = generator.send(data)
101+
self.assertIsNotNone(loss)
102+
avg_loss = fluid.layers.mean(x=loss)
103+
fluid.backward.append_backward(loss=avg_loss)
104+
105+
exe = fluid.Executor(place)
106+
exe.run(startup)
107+
return exe.run(main, feed=feed, fetch_list=fetch)
108+
109+
def _assert_same_(self, fetch, *args):
110+
"""
111+
Assert the return values of `run_test` are same.
112+
Args:
113+
fetch: Fetch list. Used for print error message
114+
*args: The fetch result lists of each situations.
115+
116+
Returns:
117+
None
118+
119+
Raises:
120+
AssertionError
121+
122+
"""
123+
124+
def _impl_(a, b, fetch_id, item_id):
125+
item_str = ['CPU', 'ParallelCPU', 'GPU', 'ParallelGPU']
126+
flag = numpy.allclose(a, b, rtol=0.1)
127+
self.assertTrue(flag, "The {0} are different in {1}".format(
128+
fetch[fetch_id], item_str[item_id]))
129+
130+
for i, items in enumerate(zip(*args)):
131+
self.assertGreater(len(items), 0)
132+
for j in range(1, len(items)):
133+
_impl_(items[0], items[j], fetch_id=i, item_id=j)
134+
135+
136+
class ParallelOpTest(BaseParallelForTest):
137+
def test_simple_fc(self):
138+
def __network__():
139+
x = fluid.layers.data(shape=[784], dtype='float32', name='img')
140+
# FIXME: This is a bug of parallel.do
141+
x.stop_gradient = False
142+
x = yield x
143+
hidden = fluid.layers.fc(input=x, size=200, param_attr='fc1.w')
144+
loss = fluid.layers.mean(x=hidden)
145+
yield loss
146+
147+
self.run_test(
148+
callback=__network__,
149+
feed={
150+
'img':
151+
numpy.random.random(size=(128 * 3, 784)).astype('float32')
152+
},
153+
fetch='fc1.w@GRAD')
43154

44155

45156
if __name__ == '__main__':

0 commit comments

Comments
 (0)