Skip to content

Commit 4178818

Browse files
authored
bug fix (#21)
Fix ODPS table io_slicing type error. Fix restoring checkpoint in distributed evaluation. Fix hang when enabling amp dynamic loss scale and gradient accumulation.
1 parent 6388b3c commit 4178818

7 files changed

Lines changed: 60 additions & 23 deletions

File tree

epl/parallel/graph_editor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ def table_io_slicing(self, dataset_api_op):
117117
"""Slicing table to balance data load among all model replicas."""
118118
slice_id = 0
119119
all_devices = dataset_api_op.taskgraph.virtual_device.all_devices
120-
list.sort(all_devices)
120+
all_devices = sorted(all_devices)
121121
if self._graph.num_constructors > 1:
122122
total_num_slices = len(all_devices)
123123
for idx, dev in enumerate(all_devices):

epl/parallel/hooks.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -210,23 +210,25 @@ def apply_gradients(self, grads_and_vars, *args, **kwargs):
210210
with ModelPhase(ModelPhase.APPLY):
211211
if not apply_opt:
212212
apply_fn = lambda: fn(self, grads_and_vars, *args, **kwargs)
213-
elif zero_enabled():
214-
apply_fn = lambda: apply_zero(self, fn, grads_and_vars,
215-
global_step, ga_iters,
216-
num_apply_group, name)
217213
elif ga_enabled():
218214
apply_fn = lambda: apply_ga(self, fn, grads_and_vars,
219215
global_step, ga_iters,
220216
num_apply_group, name)
221-
elif num_apply_group > 1:
222-
apply_fn = lambda: apply_grad_group(self, fn, grads_and_vars,
223-
num_apply_group,
224-
global_step, name=name)
225217
else:
226-
apply_fn = lambda: fn(self, grads_and_vars, *args, **kwargs)
218+
if zero_enabled():
219+
apply_fn = lambda: apply_zero(self, fn, grads_and_vars,
220+
global_step, ga_iters,
221+
num_apply_group, name)
222+
223+
elif num_apply_group > 1:
224+
apply_fn = lambda: apply_grad_group(self, fn, grads_and_vars,
225+
num_apply_group,
226+
global_step, name=name)
227+
else:
228+
apply_fn = lambda: fn(self, grads_and_vars, *args, **kwargs)
227229

228-
if apply_opt and amp_enabled() and Env.get().config.amp.loss_scale == "dynamic":
229-
return amp_update(grads_and_vars, apply_fn, name)
230+
if amp_enabled() and Env.get().config.amp.loss_scale == "dynamic":
231+
return amp_update(grads_and_vars, apply_fn, name)
230232
return apply_fn()
231233
return apply_gradients
232234

@@ -578,7 +580,8 @@ def restore(self, sess, save_path):
578580
# TODO(wangang.wa): This code will be removed after merging
579581
# variables for split strategy.
580582
if Graph.get().first_constructor_rank == Env.get().cluster.worker_index or \
581-
any(taskgraph.strategy_context.split_strategy is not None for taskgraph in Graph.get().taskgraphs):
583+
any(taskgraph.strategy_context.split_strategy is not None for taskgraph in Graph.get().taskgraphs) or \
584+
not Graph.get().need_parallel:
582585
with ModelPhase(ModelPhase.SAVE_AND_RESTORE):
583586
ret = fn(self, sess, save_path)
584587
return ret

epl/runtime/gradient_accumulation.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
from epl.ir.graph import Graph
3434
from epl.runtime.optimizer_helper import filter_none_grads, \
3535
apply_grad_group
36+
from epl.runtime.amp.loss_scale import amp_update
37+
from epl.runtime.amp.auto_mixed_precision import amp_enabled
38+
3639

3740
def ga_iter_num():
3841
"""Return gradient accumulation iteration number."""
@@ -72,8 +75,12 @@ def apply_accmulation(optimizer, apply_gradients_fn,
7275
grads_and_vars.append((g, v))
7376
Graph.get().add_grads_and_vars(grads_and_vars)
7477
update_ops = []
75-
apply_op = apply_grad_group(optimizer, apply_gradients_fn, grads_and_vars,
76-
ngroup, global_step, "epl_apply_grad_ga")
78+
apply_fn = lambda: apply_grad_group(optimizer, apply_gradients_fn, grads_and_vars,
79+
ngroup, global_step, "epl_apply_grad_ga")
80+
if amp_enabled() and Env.get().config.amp.loss_scale == "dynamic":
81+
apply_op = amp_update(grads_and_vars, apply_fn, 'amp_update')
82+
else:
83+
apply_op = apply_fn()
7784
update_ops.append(apply_op)
7885
with ops.control_dependencies(update_ops):
7986
clear_ops = [state_ops.assign(s, array_ops.zeros_like(s)) for s in slots]

epl/utils/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@
1414
# =============================================================================
1515
"""EPL version."""
1616

17-
VERSION = "0.3.0"
17+
VERSION = "0.6.0"

tests/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ GPU_8 = 0,1,2,3,4,5,6,7
88

99
.PHONY: test
1010
test:
11-
PYTHONPATH=../ $(PYTHON) -m epl.utils.launcher --num_workers=2 --gpu_per_worker=1 --debug=True test_launcher.sh
1211
CUDA_VISIBLE_DEVICES='' ./launch.sh header_test.py
12+
PYTHONPATH=../ $(PYTHON) -m epl.utils.launcher --num_workers=2 --gpu_per_worker=1 --debug=True test_launcher.sh
13+
PYTHONPATH=../ $(PYTHON) -m epl.utils.launcher --num_workers=2 --gpu_per_worker=1 --debug=True test_amp_parallel.sh
1314
CUDA_VISIBLE_DEVICES=$(GPU_4) ./launch.sh strategy_new_test.py
1415
CUDA_VISIBLE_DEVICES=$(GPU_4) ./launch.sh auto_cluster_test.py
1516
CUDA_VISIBLE_DEVICES=$(GPU_2) ./launch.sh estimator_test.py

tests/dnn_data_parallel.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,19 @@
2323
import tensorflow as tf
2424
import epl
2525

26+
tf.logging.set_verbosity(tf.logging.INFO)
2627
flags = tf.app.flags
2728
flags.DEFINE_integer("max_steps", 10, "max training step")
29+
flags.DEFINE_float("learning_rate", 0.001, "learning_rate")
30+
flags.DEFINE_integer("num_micro_batch", 1, "num_micro_batch")
31+
flags.DEFINE_string("amp", None, "amp")
2832
FLAGS = tf.app.flags.FLAGS
29-
30-
epl.init()
33+
config_json = {}
34+
if FLAGS.amp:
35+
config_json["amp.level"] = "o1"
36+
config_json["amp.loss_scale"] = float(FLAGS.amp) if FLAGS.amp != "dynamic" else "dynamic"
37+
config_json["pipeline.num_micro_batch"] = FLAGS.num_micro_batch
38+
epl.init(epl.Config(config_json))
3139
epl.set_default_strategy(epl.replicate(1))
3240

3341
# dataset
@@ -43,12 +51,26 @@
4351
loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)
4452

4553
global_step = tf.train.get_or_create_global_step()
46-
optimizer = tf.train.MomentumOptimizer(learning_rate=0.001, momentum=0.9)
54+
optimizer = tf.train.MomentumOptimizer(FLAGS.learning_rate, momentum=0.9)
4755
train_op = optimizer.minimize(loss, global_step=global_step)
4856

4957
hooks = [tf.train.StopAtStepHook(last_step=FLAGS.max_steps)]
58+
max_steps = (FLAGS.max_steps+1) * FLAGS.num_micro_batch
59+
cum_steps = 0
5060
with tf.train.MonitoredTrainingSession(hooks=hooks) as sess:
51-
while not sess.should_stop():
52-
train_loss, _, step = sess.run([loss, train_op, global_step])
53-
print("Iteration %s , Loss: %s ." % (step, train_loss))
61+
while not sess.should_stop() or cum_steps > max_steps:
62+
train_ops = [loss, train_op, global_step]
63+
if FLAGS.amp:
64+
train_ops.append(epl.Env.get().parallel_information["AMP_LOSS_SCALE"]._num_good_steps) # pylint: disable=protected-access
65+
train_ops.append(epl.Env.get().parallel_information["AMP_LOSS_SCALE"]._current_loss_scale) # pylint: disable=protected-access
66+
res = sess.run(train_ops)
67+
print("Iteration %s , Loss: %s ." % (res[2], res[0]))
68+
if FLAGS.amp:
69+
num_good_steps = res[3]
70+
current_loss_scale = res[4]
71+
if FLAGS.learning_rate >= 100:
72+
assert num_good_steps <= 1
73+
assert res[2] <= 1
74+
print('good_steps: {}, current_loss_scale: {}'.format(num_good_steps, current_loss_scale))
75+
cum_steps += 1
5476
print("Train Finished.")

tests/test_amp_parallel.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
python dnn_data_parallel.py \
2+
--amp=dynamic \
3+
--num_micro_batch=3 \
4+
--learning_rate=1000

0 commit comments

Comments
 (0)