Skip to content

Commit

Permalink
improve optimizer support (PaddlePaddle#641) (PaddlePaddle#649)
Browse files Browse the repository at this point in the history
* update GetOptPrePostfix
  • Loading branch information
gglin001 authored Apr 20, 2022
1 parent 84df0d7 commit d1aa750
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 113 deletions.
69 changes: 35 additions & 34 deletions paddle/fluid/platform/device/ipu/ipu_compiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -285,42 +285,43 @@ void Compiler::LowerConstants(const Scope* scope) {

void Compiler::LowerWeights(const Scope* scope) {
VLOG(10) << "enter Compiler::LowerWeights";
// at this step, the graph doesn't contains optimizer related states
// At this step, the graph doesn't contains optimizer related states
for (auto id : graph_helper_->sorted_vars_id) {
auto* node = graph_helper_->nodes_id_map[id];
if (node->IsVar() && !node->IsCtrlVar() && node->Var()) {
if (node->Var()->Persistable() && node->inputs.empty()) {
auto var_name = node->Var()->Name();
if (resources_->tensors.count(var_name) != 0) {
VLOG(10) << "found existed one, skip lowering Weight: " << var_name;
continue;
}
if (var_name.rfind("learning_rate", 0) == 0) {
VLOG(10) << "skip learning_rate_var: " << var_name;
continue;
}
VLOG(10) << "lowering weight: " << var_name;

auto var = scope->FindVar(var_name);
if (var) {
auto tensor = var->Get<framework::LoDTensor>();
auto dtype = PdDataType2PopartType(tensor.dtype());
auto shape = std::vector<int64_t>();
for (size_t i = 0; i < tensor.dims().size(); ++i) {
shape.push_back(tensor.dims().at(i));
}
popart::TensorInfo tensor_info(dtype, shape);
popart::ConstVoidData const_data{tensor.data(), tensor_info};
if (!node->outputs.empty()) {
auto op_node = node->outputs[0];
PushNameScope(op_node->Op());
popart::TensorId result =
builder_->addInitializedInputTensor(const_data, var_name);
PopNameScope(op_node->Op());
resources_->tensors.emplace(var_name, result);
resources_->weights.push_back(var_name);
}
}
// Weights are var node and Persistable
if (node->IsVar() && !node->IsCtrlVar() && node->Var() &&
node->Var()->Persistable()) {
// Weights are Parameter in training mode
if (ipu_strategy_->is_training && !node->Var()->IsParameter()) {
continue;
}
auto var_name = node->Var()->Name();
// Some op has same input and output tensor, like batchnorm
if (resources_->tensors.count(var_name) != 0) {
VLOG(10) << "found existed one, skip lowering Weight: " << var_name;
continue;
}
VLOG(10) << "lowering weight: " << var_name;
auto var = scope->FindVar(var_name);
PADDLE_ENFORCE_NOT_NULL(
var, platform::errors::NotFound("Tensor %s is not found in the scope",
var_name));
auto tensor = var->Get<framework::LoDTensor>();
auto dtype = PdDataType2PopartType(tensor.dtype());
auto shape = std::vector<int64_t>();
for (size_t i = 0; i < tensor.dims().size(); ++i) {
shape.push_back(tensor.dims().at(i));
}
popart::TensorInfo tensor_info(dtype, shape);
popart::ConstVoidData const_data{tensor.data(), tensor_info};
if (!node->outputs.empty()) {
auto op_node = node->outputs[0];
PushNameScope(op_node->Op());
popart::TensorId result =
builder_->addInitializedInputTensor(const_data, var_name);
PopNameScope(op_node->Op());
resources_->tensors.emplace(var_name, result);
resources_->weights.push_back(var_name);
}
}
}
Expand Down
34 changes: 34 additions & 0 deletions paddle/fluid/platform/device/ipu/ipu_executor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,40 @@ namespace paddle {
namespace platform {
namespace ipu {

// Get paddle prefix and popart postfix of weight states
// Format: {popart_postfix, paddle_prefix}
std::vector<std::pair<std::string, std::string>> GetOptPrePostfix(
const std::string &opt_type) {
std::vector<std::pair<std::string, std::string>> pre_post_fix;
// Weight self
pre_post_fix.push_back(std::make_pair("", ""));

// Weight states
// TODO(alleng) support pair("Accl1___", "_moment1_{id!=0}")
if (opt_type == "adam" || opt_type == "lamb" || opt_type == "adamw") {
pre_post_fix.push_back(std::make_pair("Accl1___", "_moment1_0"));
pre_post_fix.push_back(std::make_pair("Accl2___", "_moment2_0"));
pre_post_fix.push_back(std::make_pair("Step___", "_beta1_pow_acc_0"));
} else if (opt_type == "momentum") {
pre_post_fix.push_back(std::make_pair("Accl___", "_velocity_0"));
} else if (opt_type == "adamax") {
pre_post_fix.push_back(std::make_pair("Accl1___", "_moment_0"));
pre_post_fix.push_back(std::make_pair("Accl2___", "_inf_norm__0"));
pre_post_fix.push_back(std::make_pair("Step___", "_beta1_pow_acc_0"));
} else if (opt_type == "adagrad") {
pre_post_fix.push_back(std::make_pair("Accl1___", "_moment_0"));
} else if (opt_type == "adadelta") {
pre_post_fix.push_back(std::make_pair("Accl1___", "__avg_squared_grad_0"));
pre_post_fix.push_back(
std::make_pair("Accl2___", "__avg_squared_update_0"));
} else if (opt_type == "rmsprop") {
pre_post_fix.push_back(std::make_pair("Accl1___", "_mean_square_0"));
pre_post_fix.push_back(std::make_pair("Accl2___", "_mean_grad_0"));
pre_post_fix.push_back(std::make_pair("Accl3___", "_momentum__0"));
}
return pre_post_fix;
}

Executor::~Executor() {
Detach();
session_.reset();
Expand Down
21 changes: 0 additions & 21 deletions paddle/fluid/platform/device/ipu/ipu_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -184,27 +184,6 @@ bool GetBoolEnv(std::string str) {
}
}

std::vector<std::pair<std::string, std::string>> GetOptPrePostfix(
const std::string& opt_type) {
// format: {popart_tensor_id, paddle_tensor_id}, ...
std::vector<std::pair<std::string, std::string>> pre_post_fix;

if (opt_type == "adam" || opt_type == "lamb") {
pre_post_fix.push_back(std::make_pair("", ""));
pre_post_fix.push_back(std::make_pair("Accl1___", "_moment1_0"));
pre_post_fix.push_back(std::make_pair("Accl2___", "_moment2_0"));
pre_post_fix.push_back(std::make_pair("Step___", "_beta1_pow_acc_0"));
} else if (opt_type == "sgd" || opt_type == "momentum") {
// sgd
pre_post_fix.push_back(std::make_pair("", ""));
} else {
pre_post_fix.push_back(std::make_pair("", ""));
//
}

return pre_post_fix;
}

int RequestIpus(const int num_ipus) {
// num_ipus must be pow(2, n);
return std::pow(2, ceil(log2(num_ipus)));
Expand Down
3 changes: 0 additions & 3 deletions paddle/fluid/platform/device/ipu/ipu_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,6 @@ struct ConstantOpAttrVisitor : public boost::static_visitor<void> {
void operator()(boost::blank) const { RaiseError(); }
};

std::vector<std::pair<std::string, std::string>> GetOptPrePostfix(
const std::string& opt_type);

int RequestIpus(const int num_ipus);

} // namespace ipu
Expand Down
1 change: 1 addition & 0 deletions python/paddle/fluid/tests/unittests/ipu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ if(WITH_IPU)
set_tests_properties(test_conv_op_ipu PROPERTIES TIMEOUT 300)
set_tests_properties(test_elemetwise_x_op_ipu PROPERTIES TIMEOUT 300)
set_tests_properties(test_reduce_x_op_ipu PROPERTIES TIMEOUT 600)
set_tests_properties(test_save_load_ipu PROPERTIES TIMEOUT 600)
endif()
152 changes: 97 additions & 55 deletions python/paddle/fluid/tests/unittests/ipu/test_save_load_ipu.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@

import tempfile
import unittest
from functools import partial

import numpy as np
import paddle
import paddle.optimizer
import paddle.static
from paddle.fluid.tests.unittests.ipu.op_test_ipu import IPUOpTest

Expand All @@ -28,7 +30,8 @@ def setUp(self):
self.set_atol()
self.set_data_feed()
self.set_feed_attr()
self.set_op_attrs()
self.set_attrs()
self.set_optimizer()

def set_data_feed(self):
data = np.random.uniform(size=[1, 3, 10, 10])
Expand All @@ -39,15 +42,16 @@ def set_feed_attr(self):
self.feed_shape = [x.shape for x in self.feed_fp32.values()]
self.feed_list = list(self.feed_fp32.keys())

def set_op_attrs(self):
def set_attrs(self):
self.attrs = {}
self.attrs['steps'] = 100
self.attrs['save_at_step'] = 20
self.attrs['is_training'] = True
self.attrs['opt_type'] = 'sgd'
self.attrs['enable_fp16'] = False
self.attrs['model_path'] = tempfile.TemporaryDirectory()

def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.SGD, learning_rate=1e-1)

def _test_base(self, save_otherwise_load):
scope = paddle.static.Scope()
main_prog = paddle.static.Program()
Expand All @@ -71,16 +75,8 @@ def _test_base(self, save_otherwise_load):
name='conv2d')
loss = paddle.mean(conv1)

if self.attrs['is_training']:
if self.attrs['opt_type'] == 'sgd':
sgd = paddle.optimizer.SGD(learning_rate=1e-2)
sgd.minimize(loss)
elif self.attrs['opt_type'] == 'adam':
adam = paddle.optimizer.Adam(learning_rate=1e-2)
adam.minimize(loss)
elif self.attrs['opt_type'] == 'lamb':
lamb = paddle.optimizer.Lamb(learning_rate=1e-2)
lamb.minimize(loss)
# apply optimizer
self.optimizer().minimize(loss)
fetch_list = [loss.name]

place = paddle.IPUPlace()
Expand All @@ -91,8 +87,7 @@ def _test_base(self, save_otherwise_load):
paddle.static.load(main_prog, self.attrs['model_path'].name)

ipu_strategy = paddle.static.IpuStrategy()
ipu_strategy.set_graph_config(
is_training=self.attrs['is_training'])
ipu_strategy.set_graph_config(is_training=True)
ipu_strategy.set_precision_config(
enable_fp16=self.attrs['enable_fp16'])
ipu_program = paddle.static.IpuCompiledProgram(
Expand Down Expand Up @@ -131,62 +126,109 @@ def test_base(self):
self.attrs['model_path'].cleanup()


class TestMomentum(TestBase):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Momentum, learning_rate=1e-1)


class TestAdam(TestBase):
def set_op_attrs(self):
self.attrs = {}
self.attrs['steps'] = 100
self.attrs['save_at_step'] = 20
self.attrs['is_training'] = True
self.attrs['opt_type'] = 'adam'
self.attrs['enable_fp16'] = False
self.attrs['model_path'] = tempfile.TemporaryDirectory()
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Adam, learning_rate=1e-1)


class TestLamb(TestBase):
def set_op_attrs(self):
self.attrs = {}
self.attrs['steps'] = 100
self.attrs['save_at_step'] = 20
self.attrs['is_training'] = True
self.attrs['opt_type'] = 'lamb'
self.attrs['enable_fp16'] = False
self.attrs['model_path'] = tempfile.TemporaryDirectory()
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Lamb, learning_rate=1e-1)


class TestAdamW(TestBase):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.AdamW, learning_rate=1e-1)


class TestAdamax(TestBase):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Adamax, learning_rate=1e-1)


class TestAdagrad(TestBase):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Adagrad, learning_rate=1e-1)


class TestAdadelta(TestBase):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Adagrad, learning_rate=1e-1)


class TestRMSProp(TestBase):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.RMSProp, learning_rate=1e-1)


class TestCenteredRMSProp(TestBase):
def set_optimizer(self):
self.optimizer = partial(
paddle.optimizer.RMSProp, learning_rate=1e-1, centered=True)


@unittest.skipIf(IPUOpTest.use_ipumodel(), "skip for ipumodel")
class TestSGDFP16(TestBase):
def set_op_attrs(self):
def set_attrs(self):
self.attrs = {}
self.attrs['steps'] = 100
self.attrs['save_at_step'] = 20
self.attrs['is_training'] = True
self.attrs['opt_type'] = 'sgd'
self.attrs['enable_fp16'] = True
self.attrs['model_path'] = tempfile.TemporaryDirectory()

def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.SGD, learning_rate=1e-1)

@unittest.skipIf(IPUOpTest.use_ipumodel(), "skip for ipumodel")
class TestAdamFP16(TestBase):
def set_op_attrs(self):
self.attrs = {}
self.attrs['steps'] = 100
self.attrs['save_at_step'] = 20
self.attrs['is_training'] = True
self.attrs['opt_type'] = 'adam'
self.attrs['enable_fp16'] = True
self.attrs['model_path'] = tempfile.TemporaryDirectory()

class TestMomentumFp16(TestSGDFP16):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Momentum, learning_rate=1e-1)

@unittest.skipIf(IPUOpTest.use_ipumodel(), "skip for ipumodel")
class TestLambFP16(TestBase):
def set_op_attrs(self):
self.attrs = {}
self.attrs['steps'] = 100
self.attrs['save_at_step'] = 20
self.attrs['is_training'] = True
self.attrs['opt_type'] = 'lamb'
self.attrs['enable_fp16'] = True
self.attrs['model_path'] = tempfile.TemporaryDirectory()

class TestAdamFP16(TestSGDFP16):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Adam, learning_rate=1e-1)


class TestLambFP16(TestSGDFP16):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Lamb, learning_rate=1e-1)


class TestAdamWFP16FP16(TestSGDFP16):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.AdamW, learning_rate=1e-1)


class TestAdamaxFP16(TestSGDFP16):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Adamax, learning_rate=1e-1)


class TestAdagradFP16(TestSGDFP16):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Adagrad, learning_rate=1e-1)


class TestAdadeltaFP16(TestSGDFP16):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.Adagrad, learning_rate=1e-1)


class TestRMSPropFP16(TestSGDFP16):
def set_optimizer(self):
self.optimizer = partial(paddle.optimizer.RMSProp, learning_rate=1e-1)


class TestCenteredRMSPropFP16(TestSGDFP16):
def set_optimizer(self):
self.optimizer = partial(
paddle.optimizer.RMSProp, learning_rate=1e-1, centered=True)


if __name__ == "__main__":
Expand Down

0 comments on commit d1aa750

Please sign in to comment.