Files
paddlepaddle--paddle/python/paddle/distributed/ps/the_one_ps.py
T
2026-07-13 12:40:42 +08:00

1782 lines
64 KiB
Python
Executable File

# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import warnings
from google.protobuf import text_format
import paddle
from paddle.distributed import fleet
from paddle.distributed.communicator import Communicator, HeterClient
from paddle.distributed.fleet.base.private_helper_function import (
wait_server_ready,
)
from paddle.distributed.fleet.proto import the_one_ps_pb2
from paddle.distributed.fleet.runtime.runtime_base import RuntimeBase
from paddle.distributed.ps.coordinator import Coordinator
from paddle.distributed.ps.utils.public import * # noqa: F403
from paddle.framework import core
from paddle.static import CompiledProgram, Executor, Program
__all__ = [
'Table',
'SparseTable',
'GeoSparseTable',
'BarrierTable',
'TensorTable',
'DenseTable',
]
def get_program_by_id(context, program_id):
programs = context["origin_main_programs"]
for i, program in enumerate(programs):
if id(program) == program_id:
return program, context["origin_startup_programs"][i], i
return None, None, None
def parse_table_class(varname, program_id, context):
main_program, startup_program, idx = get_program_by_id(context, program_id)
for op in main_program.global_block().ops:
if not is_distributed_sparse_op(op) and not is_sparse_op(op):
continue
param_name = op.input("W")[0]
if (
param_name == varname
and op.type == "lookup_table"
or op.type == "lookup_table_v2"
):
if op.has_attr('table_class') and op.attr("table_class") != "none":
return op.attr('table_class')
else:
return "MemorySparseTable"
def check_embedding_dim(accessor_proto, varname, program_id, context):
main_program, startup_program, idx = get_program_by_id(context, program_id)
embedding_dim = 0
for var in main_program.list_vars():
if var.name == varname:
embedding_dim = var.shape[1]
print(f'new var: {var}, {embedding_dim}, {accessor_proto.fea_dim}')
break
fea_dim = accessor_proto.fea_dim
if accessor_proto.accessor_class == "SparseAccessor":
if fea_dim != embedding_dim + 2:
raise ValueError(
f"The fea_dim is wrong, it will be sparse_embedding_dim + 2: {embedding_dim + 2}, but got {fea_dim}"
)
else:
if fea_dim != embedding_dim:
raise ValueError(
f"The fea_dim is wrong, it will be sparse_embedding_dim: {embedding_dim}, but got {fea_dim}"
)
embedx_dim = accessor_proto.embedx_dim
if accessor_proto.accessor_class == "SparseAccessor":
if embedx_dim != embedding_dim - 1:
raise ValueError(
f"The embedx_dim is wrong, it will be sparse_embedding_dim - 1: {embedding_dim - 1}, but got {embedx_dim}"
)
else:
if embedx_dim != embedding_dim - 3:
raise ValueError(
f"The embedx_dim is wrong, it will be sparse_embedding_dim - 3: {embedding_dim - 3}, but got {embedx_dim}"
)
class Service:
def __init__(self):
pass
def _set(self, service_proto):
service_proto.server_class = "BrpcPsServer"
service_proto.client_class = "BrpcPsClient"
service_proto.service_class = "BrpcPsService"
service_proto.start_server_port = 0
service_proto.server_thread_num = 12
class GpuService(Service):
def __init__(self):
super().__init__()
def _set(self, service_proto):
service_proto.server_class = 'PsLocalServer'
service_proto.client_class = 'PsLocalClient'
class Accessor:
def __init__(self):
self.accessor_class = ""
self.optimizer = None
self.feature_dim = 0
self.embedding_dim = 0
# TableAccessorParameter accessor
def _set(
self, accessor_proto, varname, program_id, context, common_accessor
):
main_program, startup_program, idx = get_program_by_id(
context, program_id
)
embedding_dim = 0
for var in main_program.list_vars():
if var.name == varname:
embedding_dim = var.shape[1]
break
if not accessor_proto.HasField("accessor_class"):
# DownpourSparseValueAccessor
if context['use_ps_gpu']:
accessor_proto.accessor_class = "CtrDymfAccessor"
else:
accessor_proto.accessor_class = "SparseAccessor"
if not accessor_proto.HasField("fea_dim"):
if accessor_proto.accessor_class == "SparseAccessor":
accessor_proto.fea_dim = embedding_dim + 2
else:
accessor_proto.fea_dim = embedding_dim
if not accessor_proto.HasField("embedx_dim"):
if accessor_proto.accessor_class == "SparseAccessor":
accessor_proto.embedx_dim = embedding_dim - 1
else:
accessor_proto.embedx_dim = embedding_dim - 3
if not accessor_proto.HasField("embedx_threshold"):
accessor_proto.embedx_threshold = 0
graph_sgd_param = accessor_proto.graph_sgd_param
if not graph_sgd_param.HasField("nodeid_slot"):
graph_sgd_param.nodeid_slot = 9008
if not graph_sgd_param.HasField("feature_learning_rate"):
graph_sgd_param.feature_learning_rate = 0.05
ctr_accessor_param = accessor_proto.ctr_accessor_param
if not ctr_accessor_param.HasField("zero_init"):
ctr_accessor_param.zero_init = True
if accessor_proto.embedx_dim == 0:
ctr_accessor_param.zero_init = False
if not ctr_accessor_param.HasField("nonclk_coeff"):
ctr_accessor_param.nonclk_coeff = 0.1
if not ctr_accessor_param.HasField("click_coeff"):
ctr_accessor_param.click_coeff = 1.0
if not ctr_accessor_param.HasField("base_threshold"):
ctr_accessor_param.base_threshold = 0
if not ctr_accessor_param.HasField("delta_threshold"):
ctr_accessor_param.delta_threshold = 0
if not ctr_accessor_param.HasField("delta_keep_days"):
ctr_accessor_param.delta_keep_days = 16
if not ctr_accessor_param.HasField("show_click_decay_rate"):
ctr_accessor_param.show_click_decay_rate = 1
if not ctr_accessor_param.HasField("delete_threshold"):
ctr_accessor_param.delete_threshold = 0
if not ctr_accessor_param.HasField("delete_after_unseen_days"):
ctr_accessor_param.delete_after_unseen_days = 30
if not ctr_accessor_param.HasField("ssd_unseenday_threshold"):
ctr_accessor_param.ssd_unseenday_threshold = 1
for sgd_param in [
accessor_proto.embed_sgd_param,
accessor_proto.embedx_sgd_param,
]:
if not sgd_param.HasField("name"):
if common_accessor.accessor_class == "sgd":
sgd_param.name = "SparseNaiveSGDRule"
if common_accessor.accessor_class == "adam":
sgd_param.name = "SparseAdamSGDRule"
else: # for fl-ps, because geo accessor is 'sum'
sgd_param.name = "SparseAdamSGDRule"
if (
sgd_param.name == "SparseAdaGradSGDRule"
or sgd_param.name == "StdAdaGradSGDRule"
):
if not sgd_param.adagrad.HasField("learning_rate"):
sgd_param.adagrad.learning_rate = 0.05
if not sgd_param.adagrad.HasField("initial_g2sum"):
sgd_param.adagrad.initial_g2sum = 3.0
if not sgd_param.adagrad.HasField("initial_range"):
sgd_param.adagrad.initial_range = 0.0001
if len(sgd_param.adagrad.weight_bounds) == 0:
sgd_param.adagrad.weight_bounds.extend([-10.0, 10.0])
if sgd_param.name == "SparseNaiveSGDRule":
if not sgd_param.naive.HasField("learning_rate"):
learning_rate = common_accessor.initializers[-1].split("&")[
1
]
sgd_param.naive.learning_rate = float(learning_rate)
if not sgd_param.naive.HasField("initial_range"):
initial_range = common_accessor.initializers[0].split("&")[
-1
]
sgd_param.naive.initial_range = float(initial_range)
if len(sgd_param.naive.weight_bounds) == 0:
sgd_param.naive.weight_bounds.extend([-10.0, 10.0])
if (
sgd_param.name == "SparseAdamSGDRule"
or sgd_param.name == "SparseSharedAdamSGDRule"
):
if not sgd_param.adam.HasField("learning_rate"):
learning_rate = common_accessor.initializers[-1].split("&")[
1
]
sgd_param.adam.learning_rate = float(learning_rate)
if not sgd_param.adam.HasField("initial_range"):
initial_range = common_accessor.initializers[0].split("&")[
-1
]
sgd_param.adam.initial_range = float(initial_range)
attr_list = [x.split("&") for x in common_accessor.attrs]
if (
not sgd_param.adam.HasField("beta1_decay_rate")
and common_accessor.accessor_class == "adam"
):
sgd_param.adam.beta1_decay_rate = float(attr_list[0][1])
else:
sgd_param.adam.beta1_decay_rate = 0.9
if (
not sgd_param.adam.HasField("beta2_decay_rate")
and common_accessor.accessor_class == "adam"
):
sgd_param.adam.beta2_decay_rate = float(attr_list[1][1])
else:
sgd_param.adam.beta2_decay_rate = 0.999
if (
not sgd_param.adam.HasField("ada_epsilon")
and common_accessor.accessor_class == "adam"
):
sgd_param.adam.ada_epsilon = float(attr_list[2][1])
else:
sgd_param.adam.ada_epsilon = 1e-08
if len(sgd_param.adam.weight_bounds) == 0:
sgd_param.adam.weight_bounds.extend([-10.0, 10.0])
class CommonAccessor(Accessor):
def __init__(self):
super().__init__()
self.table_name = ''
self.entry = 'none'
self.attrs = []
self.params = []
self.dims = []
self.trainer_num = 0
self.sync = False
self.initializers = []
self.opt_input_map = {}
self.opt_attr_map = {}
self.opt_init_map = {}
self.define_optimize_map()
def define_optimize_map(self):
opt_input_map = {}
opt_input_map["sgd"] = [("Param", None), ("LearningRate", 1)]
opt_input_map["adam"] = [
("Param", None),
("Moment1", None),
("Moment2", None),
("Beta1Pow", 1),
("Beta2Pow", 1),
("LearningRate", 1),
]
opt_input_map["adam_d2sum"] = [
("Param", None),
("D2Sum", None),
("G2Sum", None),
("Moment", None),
("MomentDecayRate", 1),
("AdaDecayRate", 1),
("AdaEpsilon", 1),
("LearningRate", 1),
]
opt_input_map["sum"] = [("Param", None)]
opt_input_map["naive_adagrad"] = [
("Param", None),
("G2Sum", 1),
("LearningRate", 1),
]
opt_input_map["summary"] = [("Param", None), ("SummaryDecayRate", 1)]
opt_attr_map = {}
opt_attr_map["sgd"] = []
opt_attr_map["sum"] = []
opt_attr_map["naive_adagrad"] = []
opt_attr_map["adam"] = [
("beta1", "f"),
("beta2", "f"),
("epsilon", "f"),
]
opt_attr_map["adam_d2sum"] = [
("beta1", "f"),
("beta2", "f"),
("epsilon", "f"),
]
opt_attr_map["summary"] = [("summary_decay_rate", "f")]
opt_init_map = {}
opt_init_map["gaussian_random"] = ["seed", "mean", "std"]
opt_init_map["fill_constant"] = ["value"]
opt_init_map["uniform_random"] = ["seed", "min", "max"]
opt_init_map["truncated_gaussian_random"] = ["seed", "mean", "std"]
self.opt_attr_map = opt_attr_map
self.opt_input_map = opt_input_map
self.opt_init_map = opt_init_map
def parse_entry(self, varname, program_id, context):
main_program, startup_program, idx = get_program_by_id(
context, program_id
)
for op in main_program.global_block().ops:
if not is_distributed_sparse_op(op) and not is_sparse_op(op):
continue
param_name = op.input("W")[0]
if param_name == varname and op.type == "lookup_table":
self.entry = op.attr('entry')
break
if param_name == varname and op.type == "lookup_table_v2":
self.entry = "none"
break
def get_shard(self, total_dim, shard_num, pserver_id):
blocksize = int(total_dim / shard_num + 1)
if blocksize * (pserver_id + 1) <= total_dim:
return blocksize
else:
if blocksize * pserver_id < total_dim:
return total_dim - blocksize * pserver_id
else:
return 0
def get_initializer_attr(self, value_name, o_startup_program):
l_in = "&"
attr_str = ""
origin_var_name = value_name
# print("get_initializer_attr param name:", value_name)
for op in o_startup_program.global_block().ops:
if (
op.type in self.opt_init_map.keys()
and origin_var_name == op.output("Out")[0]
):
init_attr = [op.type]
# print("get_initializer_attr op type:", op.type)
for attr in self.opt_init_map[op.type]:
# print("get_initializer_attr opt_init_map attr:", attr)
init_attr.append(str(op.attr(attr)))
# print("get_initializer_attr op attr:", str(op.attr(attr)))
attr_str = l_in.join(init_attr)
break
return attr_str
def parse_by_optimizer(self, ctx, context):
grad_name = ctx.origin_varnames()[0]
is_sparse = ctx.is_sparse()
size = ctx.sections()[0]
single_dim = ctx.sections()[1] if ctx.is_sparse() else 1
adam_d2sum = context["user_defined_strategy"].adam_d2sum
# print("parse_by_optimizer table_id:{} is_datanorm:{}".format(
# ctx.table_id(), ctx.is_datanorm_table()))
main_program, startup_program, idx = get_program_by_id(
context, ctx.program_id()
)
pserver_id = get_role_id(context['role_maker'])
pserver_num = len(get_ps_endpoints(context['role_maker']))
optimizer_ops = get_optimize_ops(main_program)
# print("the one ps optimizer_ops:", optimizer_ops)
# print("the one ps parse_by_optimizer grad_name:", grad_name)
oop = None
for op in optimizer_ops:
if ("Param" in op.input_names) and (
op.input("Param")[0]
== context['grad_name_to_param_name'][grad_name]
):
oop = op
break
if oop is None:
raise ValueError(f"can not find optimizer for {grad_name}")
params = []
dims = []
attrs = []
initializers = []
self.trainer_num = get_trainers(context['role_maker'])
self.table_num = size
self.table_dim = single_dim
if oop.type != 'adam' and adam_d2sum:
print('optimization algorithm is not adam, set adam_d2sum False')
adam_d2sum = False
print("adam_d2sum:", adam_d2sum)
if context['ps_mode'] == DistributedMode.GEO:
param_varnames = self.opt_input_map["sum"]
attr_varnames = self.opt_attr_map["sum"]
self.accessor_class = "sum"
elif context['use_ps_gpu'] and is_sparse:
param_varnames = self.opt_input_map["naive_adagrad"]
attr_varnames = self.opt_attr_map["naive_adagrad"]
self.accessor_class = "sgd"
elif ctx.is_datanorm_table():
param_varnames = self.opt_input_map["summary"]
attr_varnames = self.opt_attr_map["summary"]
self.accessor_class = "summary"
elif adam_d2sum and not is_sparse:
param_varnames = self.opt_input_map["adam_d2sum"]
attr_varnames = self.opt_attr_map["adam_d2sum"]
self.accessor_class = "adam_d2sum"
else:
if oop.type != 'sgd' and oop.type != 'adam':
raise ValueError(
"The dense optimizer in PS is only supported SGD or Adam!"
)
param_varnames = self.opt_input_map[oop.type]
attr_varnames = self.opt_attr_map[oop.type]
self.accessor_class = oop.type
for formal_name, shape in param_varnames:
params.append(formal_name)
if self.accessor_class == "adam_d2sum":
# for dims
if shape is None:
if is_sparse:
shape = single_dim
else:
shape = self.get_shard(size, pserver_num, pserver_id)
dims.append(shape)
# for initializers
if formal_name == "Param" or formal_name == "LearningRate":
param = main_program.global_block().vars[
oop.input(formal_name)[0]
]
# TODO: for dense learning_rate, can be different from sparse lr
if (
formal_name == "LearningRate"
and param.name != "learning_rate_" + str(idx)
):
warnings.warn("will support decay soon")
param = main_program.global_block().vars[
"learning_rate_" + str(idx)
]
initializer = self.get_initializer_attr(
param.name, startup_program
)
elif formal_name == "MomentDecayRate":
initializer = "fill_constant&0.99"
elif formal_name == "AdaDecayRate":
initializer = "fill_constant&0.9999"
elif formal_name == "AdaEpsilon":
initializer = "fill_constant&1.0e-8"
else:
initializer = "fill_constant&0"
initializers.append(initializer)
elif self.accessor_class == "summary":
# for dims
if shape is None:
if is_sparse:
shape = single_dim
else:
shape = self.get_shard(size, pserver_num, pserver_id)
dims.append(shape)
# for initializers
if formal_name == "Param":
param = main_program.global_block().vars[
oop.input(formal_name)[0]
]
initializer = self.get_initializer_attr(
param.name, startup_program
)
elif formal_name == "SummaryDecayRate":
initializer = "fill_constant&0.999999"
else:
initializer = "fill_constant&0"
initializers.append(initializer)
else:
if formal_name == "G2Sum":
dims.append(1)
initializer = "fill_constant&0"
initializers.append(initializer)
else:
param = main_program.global_block().vars[
oop.input(formal_name)[0]
]
if (
formal_name == "LearningRate"
and param.name != "learning_rate_" + str(idx)
):
warnings.warn("will support decay soon")
param = main_program.global_block().vars[
"learning_rate_" + str(idx)
]
if shape is None:
if is_sparse:
shape = single_dim
else:
shape = self.get_shard(
size, pserver_num, pserver_id
)
dims.append(shape)
initializer = self.get_initializer_attr(
param.name, startup_program
)
initializers.append(initializer)
if self.accessor_class == 'summary':
datanorm_ops = get_datanorm_ops(main_program)
for op in datanorm_ops:
if ("BatchSize" in op.input_names) and (
op.input("BatchSize")[0]
== context['grad_name_to_param_name'][grad_name]
):
oop = op
break
for attr_varname, type_ in attr_varnames:
value = oop.attr(attr_varname)
attrs.append("&".join([attr_varname, str(value)]))
self.params = params
self.dims = dims
self.initializers = initializers
self.attrs = attrs
# CommonAccessorParameter common
def _set(self, proto):
proto.name = self.accessor_class
proto.table_name = self.table_name
proto.params.extend(self.params)
proto.dims.extend(self.dims)
proto.initializers.extend(self.initializers)
proto.entry = self.entry
proto.trainer_num = self.trainer_num
proto.sync = self.sync
proto.table_num = self.table_num
proto.table_dim = self.table_dim
proto.attr = "#".join(self.attrs)
class Tensor:
def __init__(self, tensor_dict):
self.tensor_dict = tensor_dict
def _set(self, tensor_proto):
tensor_proto.main_program_id = self.tensor_dict.get(
"main_program_id", 0
)
tensor_proto.startup_program_id = self.tensor_dict.get(
"startup_program_id", 0
)
tensor_proto.feed_var_name = self.tensor_dict.get("feed_var_name", '')
tensor_proto.fetch_var_name = self.tensor_dict.get("fetch_var_name", '')
tensor_proto.tensor_table_class = self.tensor_dict.get(
"tensor_table_class", ''
)
class Table:
def __init__(self):
self.table_class = None
self.shard_num = -1
self.type = None
self.accessor = Accessor()
self.shard_num = 256
self.common = CommonAccessor()
self.tensor = None
def _set(self, table_proto):
pass
class BarrierTable(Table):
def __init__(self, context, idx):
super().__init__()
self.type = None
self.shard_num = 256
self.accessor.accessor_class = 'CommMergeAccessor'
self.common.attrs = ""
self.common.dims = []
self.common.params = []
self.is_heter_ps_mode = context['is_heter_ps_mode']
self.role_maker = context['role_maker']
self.idx = idx
self.is_sync = context['is_sync']
def _set(self, table_proto):
table_proto.table_id = self.idx
table_proto.table_class = 'BarrierTable'
table_proto.shard_num = 256
table_proto.type = the_one_ps_pb2.PS_OTHER_TABLE
table_proto.accessor.accessor_class = "CommMergeAccessor"
table_proto.accessor.fea_dim = 0
table_proto.accessor.embedx_dim = 0
table_proto.common.name = ""
table_proto.common.table_name = "barrier_table"
table_proto.common.sync = self.is_sync
table_proto.common.entry = 'none'
trainer_num = get_trainers(self.role_maker)
if self.is_heter_ps_mode:
trainer_num += len(self.role_maker._get_heter_worker_endpoints())
table_proto.common.trainer_num = trainer_num
class TensorTable(Table):
def __init__(self, idx, tensor_dict, role_maker):
super().__init__()
self.idx = idx
self.tensor_dict = tensor_dict
self.role_maker = role_maker
def _set(self, table_proto):
table_proto.table_id = self.idx
table_proto.type = the_one_ps_pb2.PS_OTHER_TABLE
table_proto.table_class = self.tensor_dict.get("tensor_table_class", '')
table_proto.accessor.accessor_class = "CommMergeAccessor"
table_proto.common.table_name = self.tensor_dict.get(
"feed_var_name", ''
)
table_proto.common.trainer_num = get_trainers(self.role_maker)
tensor = Tensor(self.tensor_dict)
tensor._set(table_proto.tensor)
class SparseTable(Table):
def __init__(self, context, send_ctx):
super().__init__()
self.context = context
self.ctx = send_ctx
self.type = None
self.table_class = 'MemorySparseTable'
self.accessor = Accessor()
def _set(self, table_proto):
ctx = self.ctx
if (
ctx.is_tensor_table()
or len(ctx.origin_varnames()) < 1
or (not ctx.is_sparse())
):
return
table_proto.table_id = ctx.table_id()
table_proto.table_class = self.table_class
table_proto.type = the_one_ps_pb2.PS_SPARSE_TABLE
table_proto.shard_num = self.shard_num
if table_proto.sparse_table_cache_file_num > len(
get_ps_endpoints(self.context['role_maker'])
):
table_proto.sparse_table_cache_file_num = len(
get_ps_endpoints(self.context['role_maker'])
)
self.common.table_name = self.context['grad_name_to_param_name'][
ctx.origin_varnames()[0]
]
self.common.parse_by_optimizer(ctx, self.context)
self.common.parse_entry(
self.common.table_name, ctx.program_id(), self.context
)
self.common.sync = True if self.context['is_sync'] else False
self.common._set(table_proto.common)
print(f'new table_name: {self.common.table_name}')
all_table_proto = self.context[
"user_defined_strategy"
].sparse_table_configs
usr_table_proto = all_table_proto.add()
for proto in all_table_proto:
if proto.table_name == self.common.table_name:
usr_table_proto = proto
break
if usr_table_proto.HasField("table_class"):
table_proto.table_class = usr_table_proto.table_class
else:
table_proto.table_class = 'MemorySparseTable'
warnings.warn("The PS mode must use MemorySparseTable.")
if usr_table_proto.HasField("shard_num"):
table_proto.shard_num = usr_table_proto.shard_num
else:
if self.context['use_ps_gpu']:
table_proto.shard_num = 37
warnings.warn(
"The shard_num of sparse table is not set, use default value 37 in gpups."
)
else:
table_proto.shard_num = 1000
warnings.warn(
"The shard_num of sparse table is not set, use default value 1000 in cpups."
)
if usr_table_proto.HasField("enable_sparse_table_cache"):
table_proto.enable_sparse_table_cache = (
usr_table_proto.enable_sparse_table_cache
)
if usr_table_proto.HasField("sparse_table_cache_rate"):
table_proto.sparse_table_cache_rate = (
usr_table_proto.sparse_table_cache_rate
)
if usr_table_proto.HasField("sparse_table_cache_file_num"):
table_proto.sparse_table_cache_file_num = (
usr_table_proto.sparse_table_cache_file_num
)
if usr_table_proto.HasField("enable_revert"):
table_proto.enable_revert = usr_table_proto.enable_revert
if usr_table_proto.HasField("shard_merge_rate"):
table_proto.shard_merge_rate = usr_table_proto.shard_merge_rate
if usr_table_proto.accessor.ByteSize() == 0:
warnings.warn(
"The accessor of sparse table is not set, use default value."
)
if usr_table_proto.HasField("use_gpu_graph"):
table_proto.use_gpu_graph = usr_table_proto.use_gpu_graph
table_proto.accessor.ParseFromString(
usr_table_proto.accessor.SerializeToString()
)
self.accessor._set(
table_proto.accessor,
self.common.table_name,
ctx.program_id(),
self.context,
self.common,
)
check_embedding_dim(
table_proto.accessor,
self.common.table_name,
ctx.program_id(),
self.context,
)
class GeoSparseTable(SparseTable):
def __init__(self, context, send_ctx):
super().__init__(context, send_ctx)
self.table_class = "MemorySparseGeoTable"
if self.context['ps_mode'] != DistributedMode.GEO:
raise ValueError("not geo sparse table!")
def _set(self, table_proto):
ctx = self.ctx
if (
ctx.is_tensor_table()
or len(ctx.origin_varnames()) < 1
or (not ctx.is_sparse())
):
return
table_proto.table_id = ctx.table_id()
table_proto.table_class = self.table_class
table_proto.type = the_one_ps_pb2.PS_SPARSE_TABLE
table_proto.shard_num = self.shard_num
table_proto.accessor.accessor_class = 'CommMergeAccessor'
table_proto.accessor.fea_dim = ctx.sections()[0]
table_proto.accessor.embedx_dim = ctx.sections()[1]
self.common.table_name = self.context['grad_name_to_param_name'][
ctx.origin_varnames()[0]
]
self.common.parse_by_optimizer(ctx, self.context)
self.common.parse_entry(
self.common.table_name, ctx.program_id(), self.context
)
self.common.sync = False
self.common._set(table_proto.common)
class DenseTable(Table):
def __init__(self, context, send_ctx):
super().__init__()
self.context = context
self.ctx = send_ctx
self.accessor = Accessor()
def _set(self, table_proto):
ctx = self.ctx
if (
ctx.is_tensor_table()
or len(ctx.origin_varnames()) < 1
or (ctx.is_sparse())
):
return
table_proto.table_id = ctx.table_id()
table_proto.type = the_one_ps_pb2.PS_DENSE_TABLE
table_proto.table_class = "MemoryDenseTable"
table_proto.shard_num = 256
table_proto.accessor.accessor_class = 'CommMergeAccessor'
table_proto.accessor.fea_dim = ctx.sections()[0]
table_proto.accessor.embedx_dim = 1
self.common.table_name = "MergedDense"
self.common.parse_by_optimizer(ctx, self.context)
self.common.parse_entry(
self.common.table_name, ctx.program_id(), self.context
)
self.common.sync = True if self.context['is_sync'] else False
self.common._set(table_proto.common)
class Server:
def __init__(self):
pass
def _set(self):
pass
class DownpourServer(Server):
def __init__(self):
super().__init__()
def _set(self):
pass
class Worker:
def __init__(self):
pass
def _set(self):
pass
class DownpourWorker(Worker):
def __init__(self):
super().__init__()
def _set(self):
pass
class fsClient:
def __init__(self, fs_client_param):
self.fs_client_param = fs_client_param
def _set(self, proto):
if not text_format.MessageToString(self.fs_client_param):
return
proto.uri = self.fs_client_param.uri
proto.user = self.fs_client_param.user
proto.passwd = self.fs_client_param.passwd
proto.hadoop_bin = self.fs_client_param.hadoop_bin
class PsDescBuilder:
def __init__(self, context):
self.context = context
self.is_sync = context['is_sync']
self.ps_mode = context['ps_mode']
self.is_heter_ps_mode = context['is_heter_ps_mode']
self.use_ps_gpu = context['use_ps_gpu']
self.barrier_table_id = None
self.send_ctx = get_the_one_send_context(
self.context, split_dense_table=self.is_heter_ps_mode
)
self.tensor_table_dict = {} # TODO
self._server_sub_program = []
self.tables = self._get_tables()
self.service = self._get_service()
self.fs_client = self._get_fs_client()
self.ps_desc = the_one_ps_pb2.PSParameter()
self.fl_desc = the_one_ps_pb2.FLParameter()
def _get_tensor_tables(self):
program_idx = 0
if not self.tensor_table_dict:
self._server_sub_program.append(Program().desc)
tables = []
for table_name in self.tensor_table_dict:
tables.append(
globals()['TensorTable'](
len(tables), tensor_dict, self.context['role_maker']
)
)
program_idx += 1
return tables
def _get_tables(self):
tables = []
for idx, (name, ctx) in enumerate(self.send_ctx.items()):
print("idx, name, ctx:", idx, name, ctx)
if ctx.is_sparse():
if self.ps_mode == DistributedMode.GEO:
if (
self.context['local_sparse']
and name[:-5] in self.context['local_sparse']
) or (not self.context['local_sparse']):
tables.append(
globals()['GeoSparseTable'](self.context, ctx)
)
else:
tables.append(
globals()['SparseTable'](self.context, ctx)
)
else:
tables.append(globals()['SparseTable'](self.context, ctx))
else:
if not self.use_ps_gpu:
tables.append(globals()['DenseTable'](self.context, ctx))
self.tensor_tables = self._get_tensor_tables()
tables.extend(self.tensor_tables)
tables.append(globals()['BarrierTable'](self.context, len(tables)))
return tables
def _get_service(self):
if self.use_ps_gpu:
return GpuService()
else:
return Service()
def _get_fs_client(self):
return fsClient(self.context["user_defined_strategy"].fs_client_param)
def build_fl_client_desc(self, client_info):
pass
def build_worker_desc(self):
for table in self.tables:
table_proto = self.ps_desc.worker_param.downpour_worker_param.downpour_table_param.add()
table._set(table_proto)
table_proto = self.ps_desc.server_param.downpour_server_param.downpour_table_param.add()
table._set(table_proto)
if type(table) == BarrierTable and self.barrier_table_id is None:
self.barrier_table_id = table.idx
self.service._set(
self.ps_desc.server_param.downpour_server_param.service_param
)
self.fs_client._set(self.ps_desc.fs_client_param)
return text_format.MessageToString(self.ps_desc)
def build_server_desc(self):
self.sparse_table_maps = {}
for table in self.tables:
table_proto = self.ps_desc.server_param.downpour_server_param.downpour_table_param.add()
table._set(table_proto)
if (
table_proto.type == the_one_ps_pb2.PS_SPARSE_TABLE
and table_proto.common is not None
):
self.sparse_table_maps[table_proto.common.table_name] = (
table_proto.table_id
)
self.service._set(
self.ps_desc.server_param.downpour_server_param.service_param
)
self.fs_client._set(self.ps_desc.fs_client_param)
return text_format.MessageToString(self.ps_desc)
class TheOnePSRuntime(RuntimeBase):
def __init__(self):
super().__init__()
self._communicator = None
self._server = None
self._worker = core.DistFleetWrapper()
self._coordinator = None
self._server_sub_program = []
self._heter_client = None
self._send_ctx = None
def _set_basic_info(self, context):
self.context = context
self.role_maker = context["role_maker"]
self.role_id = get_role_id(self.role_maker)
self.debug = bool(int(os.getenv("PSERVER_DEBUG", "0")))
self.origin_main_program = context["origin_main_program"]
self.origin_main_programs = context.get(
"origin_main_programs", [self.origin_main_program]
)
self.context["origin_main_programs"] = self.origin_main_programs
self.context["origin_startup_programs"] = context.get(
'origin_startup_programs', [context['origin_startup_program']]
)
self.context['is_heter_ps_mode'] = (
self.role_maker._is_heter_parameter_server_mode
)
self.is_heter_ps_mode = self.context['is_heter_ps_mode']
self.context['trainer'] = TrainerRuntimeConfig(
context['valid_strategy']
)
self.context['ps_mode'] = self.context['trainer'].mode
self.context['use_ps_gpu'] = context['valid_strategy'].a_sync_configs[
'use_ps_gpu'
]
self.context['use_gpu_graph'] = context[
'valid_strategy'
].a_sync_configs['use_gpu_graph']
self.context['is_sync'] = (
True if self.context['ps_mode'] == DistributedMode.SYNC else False
)
self.context['grad_name_to_param_name'] = {}
self.context['tensor_table'] = {}
# FL
self.context['local_sparse'] = context[
"user_defined_strategy"
].trainer_desc_configs["local_sparse"]
self.context['remote_sparse'] = context[
"user_defined_strategy"
].trainer_desc_configs["remote_sparse"]
print(
"fl-ps > local_sparse: {}, remote_sparse: {}".format(
self.context['local_sparse'], self.context['remote_sparse']
)
)
build_var_distributed(self.context)
self.trainer_endpoints = get_trainer_endpoints(self.role_maker)
self.endpoints = get_ps_endpoints(self.role_maker)
self.string_hosts = []
for idx, ep in enumerate(self.endpoints):
host, port = ep.split(":")
pshost = core.PSHost(host, int(port), idx)
self.string_hosts.append(pshost.serialize_to_string())
self.with_coordinator = self.role_maker._with_coordinator
self.coordinator_hosts = []
if self.with_coordinator:
print(f"fl-ps > all ps addrs: {self.string_hosts}")
coordinator_endpoints = self.role_maker._get_coordinator_endpoints()
for idx, ep in enumerate(coordinator_endpoints):
ip, port = ep.split(":")
pshost = core.PSHost(ip, int(port), idx)
self.coordinator_hosts.append(pshost.serialize_to_string())
self.ps_desc_builder = PsDescBuilder(self.context)
def _init_all_params(self, scopes, send_ctx, recv_map):
all_var_names = []
for name, ctx in send_ctx.items():
if ctx.is_sparse():
continue
_, _, idx = get_program_by_id(self.context, ctx.program_id())
scope = scopes[idx]
table_id = ctx.table_id()
var_names = recv_map[table_id]
# print("init params:", idx, table_id, var_names)
self._worker.push_dense_params(scope, table_id, var_names)
all_var_names.extend(var_names)
return all_var_names
def _pull_all_dense(self, scopes, send_ctx, recv_map):
all_var_names = []
for name, ctx in send_ctx.items():
if ctx.is_sparse():
continue
_, _, idx = get_program_by_id(self.context, ctx.program_id())
scope = scopes[idx]
table_id = ctx.table_id()
var_names = recv_map[table_id]
# print("pull all dense:", idx, table_id, var_names)
self._worker.pull_dense_params(scope, table_id, var_names)
all_var_names.extend(var_names)
return all_var_names
def _init_params(self, program, scope, send_ctx, recv_map):
all_var_names = []
for name, ctx in send_ctx.items():
if ctx.is_sparse():
continue
if ctx.program_id() != id(program):
continue
table_id = ctx.table_id()
var_names = recv_map[table_id]
# print("init params:", table_id, var_names)
self._worker.push_dense_params(scope, table_id, var_names)
all_var_names.extend(var_names)
return all_var_names
def _pull_dense(self, program, scope, send_ctx, recv_map):
all_var_names = []
for name, ctx in send_ctx.items():
if ctx.is_sparse():
continue
if ctx.program_id() != id(program):
continue
table_id = ctx.table_id()
var_names = recv_map[table_id]
# print("pull dense:", table_id, var_names)
self._worker.pull_dense_params(scope, table_id, var_names)
all_var_names.extend(var_names)
return all_var_names
def _init_worker(self, scopes=None):
worker_desc = self.ps_desc_builder.build_worker_desc()
main_programs = []
if (
isinstance(self.context['loss'], list)
and len(self.context['loss']) > 1
):
for i in range(len(self.context['loss'])):
main_programs.append(self.context['loss'][i].block.program)
else:
main_programs.append(self.context['loss'].block.program)
for i in range(len(main_programs)):
if self.context['use_ps_gpu']:
if not main_programs[i]._fleet_opt:
main_programs[i]._fleet_opt = {}
main_programs[i]._fleet_opt["use_ps_gpu"] = True
gpus_env = os.getenv("FLAGS_selected_gpus")
gpus_env = [int(s) for s in gpus_env.split(",")]
main_programs[i]._fleet_opt["worker_places"] = gpus_env
if self.context['use_gpu_graph']:
main_programs[i]._fleet_opt["use_gpu_graph"] = True
def sync_strategy_envs():
kwargs = {}
kwargs["pserver_endpoints"] = (
self.role_maker._get_pserver_endpoints()
)
kwargs["trainer_id"] = self.role_maker._worker_index()
return kwargs
dense_map = get_the_one_recv_context(
self.context, split_dense_table=self.is_heter_ps_mode
)
send_ctx = get_the_one_send_context(
self.context,
split_dense_table=self.is_heter_ps_mode,
ep_list=self.endpoints,
)
self._send_ctx = send_ctx
trainer_config = self.context['trainer']
if self.debug:
print(f"worker_desc: \n{worker_desc}")
print("communicator send_ctx:")
for key in send_ctx:
print(f"{key}: {send_ctx[key]}")
for key in dense_map:
print(f"{key}: {dense_map[key]}")
kwargs = {}
kwargs['need_global_step'] = "0"
kwargs["trainer_id"] = self.role_maker._role_id()
kwargs["trainers"] = self.role_maker._worker_num()
kwargs["barrier_table_id"] = self.ps_desc_builder.barrier_table_id
if self.context['ps_mode'] == DistributedMode.SYNC:
sync_kwargs = sync_strategy_envs()
kwargs.update(sync_kwargs)
print("communicator config:", trainer_config.get_communicator_flags())
self._worker.init_worker(worker_desc, self.string_hosts, self.role_id)
if not self.is_heter_ps_mode:
self.trainer_endpoint = get_trainer_endpoint(self.role_maker)
print(f"fl-ps > trainer_endpoint: {self.trainer_endpoint}")
print(f"fl-ps > with_coordinator? {self.with_coordinator}")
print(f"fl-ps > coordinator addr: {self.coordinator_hosts}")
if self.with_coordinator:
self._worker.init_fl_worker(
self.coordinator_hosts, self.role_id, self.trainer_endpoint
)
if (
self.context['ps_mode'] == DistributedMode.GEO
or self.is_heter_ps_mode
):
self._communicator = Communicator(
trainer_config.mode,
kwargs,
trainer_config.get_communicator_flags(),
)
self._communicator.init_with_ctx(
send_ctx,
dense_map,
worker_desc,
self.string_hosts,
paddle.static.global_scope(),
)
fleet.util.barrier()
# info = self._communicator.get_client_info()
info = self._worker.get_client_info()
if isinstance(info, list) and len(info) > 0:
all_info = self.role_maker._all_gather(
info[0]
) # 收集其他 client 的 service 地址
# for unittest
if not isinstance(all_info, list):
warnings.warn("gloo may not initialize correctly")
all_info = [all_info]
# self._communicator.set_clients(all_info)
# self._communicator.create_client_to_client_connection()
self._worker.set_clients(all_info)
self._worker.create_client2client_connection()
print('create c2c connection done')
else:
print('cannot create c2c connection')
dist_strategy = self.context["valid_strategy"]
is_test = bool(int(os.getenv("TEST_MODE", "0")))
if scopes is None:
if len(self.origin_main_programs) > 1:
raise ValueError(
"You must set the scope list when you have Multiple programs"
)
scopes = [paddle.static.global_scope()]
if len(self.origin_main_programs) != len(scopes):
raise ValueError("len(programs) != len(scopes)")
self.scopes = scopes
if not is_test:
if (
self.context['ps_mode'] == DistributedMode.GEO
or self.is_heter_ps_mode
):
self._communicator.init_params(dense_map)
else:
if not self.context['use_ps_gpu']:
if self.role_id == 0:
print("entering self._init_all_params()")
self._init_all_params(scopes, send_ctx, dense_map)
fleet.util.barrier() # 保证 0 号 worker 参数 push_dense_param over
if not self.context['use_ps_gpu']:
self._pull_all_dense(scopes, send_ctx, dense_map)
fleet.util.barrier()
if (
self.context['ps_mode'] == DistributedMode.GEO
or self.is_heter_ps_mode
):
if not self._communicator.is_running():
self._communicator.start()
else:
warnings.warn("communicator has been initialized, skip")
launch_barrier = dist_strategy.a_sync_configs["launch_barrier"]
launch_barrier_flag = int(os.getenv("FLAGS_LAUNCH_BARRIER", "1"))
if launch_barrier and launch_barrier_flag:
wait_server_ready(self.role_maker._get_pserver_endpoints())
if (
self.is_heter_ps_mode
and self.role_maker._get_next_trainers() != []
):
wait_server_ready(self.role_maker._get_next_trainers())
if self.is_heter_ps_mode:
previous_trainers = []
if self.role_maker._get_previous_trainers() != []:
previous_trainers = self.role_maker._get_previous_trainers()
next_trainers = []
if self.role_maker._get_next_trainers() != []:
next_trainers = self.role_maker._get_next_trainers()
self._heter_client = HeterClient(
next_trainers, previous_trainers, self.role_maker._role_id()
) # --> HeterClient::GetInstance
def _init_coordinator(self, scopes=None):
if self._coordinator is None:
self._coordinator = Coordinator(self.string_hosts)
print(f">>> curr node ip: {self.coordinator_hosts[0]}")
print(f">>> all trainer endpoints: {self.trainer_endpoints}")
self._coordinator.start_coordinator(
self.coordinator_hosts[0], self.trainer_endpoints
)
def _make_fl_strategy(self):
if self._coordinator is None:
assert "Coordinator py object is null!"
else:
self._coordinator.make_fl_strategy()
def _init_server(self, dirname=None, var_names=None, **kwargs):
server_desc = self.ps_desc_builder.build_server_desc()
trainers = get_trainers(self.role_maker)
if self.is_heter_ps_mode:
trainers += len(self.role_maker._get_heter_worker_endpoints())
if self.debug:
print(f"server_desc: \n{server_desc}")
self._server = core.DistFleetWrapper()
self._server.init_server(
server_desc,
self.string_hosts,
self.role_id,
trainers,
self._server_sub_program,
)
dist_varnames = get_sparse_tablenames(self.origin_main_programs, True)
sparse_varnames = get_sparse_tablenames(
self.origin_main_programs, False
)
distributed_varnames = dist_varnames + sparse_varnames
if var_names is None:
load_varnames = distributed_varnames
else:
for var_name in var_names:
if var_name not in distributed_varnames:
raise ValueError(
f"fleet.init server can only load sparse variables in {distributed_varnames}"
)
load_varnames = var_names
if dirname is None or not load_varnames:
return
sparse_table_maps = self.ps_desc_builder.sparse_table_maps
dirname = os.path.normpath(dirname)
pserver_id = self.role_maker._role_id()
for var_name in load_varnames:
table_id = sparse_table_maps[var_name]
self._server.load_sparse(dirname, "0", table_id)
def _run_server(self):
ep = get_ps_endpoint(self.role_maker)
host, port = ep.split(":")
self._server.run_server(host, int(port))
def _stop_worker(self):
if self.context['ps_mode'] == DistributedMode.GEO:
self._communicator.stop()
self._worker.stop_worker()
if self.is_heter_ps_mode:
assert self._heter_client is not None, (
"heter client should not be None in heterps mode"
)
self._heter_client.stop()
@staticmethod
def __exclude_vars(exclude_var_names=[]):
def is_valid(var):
if var.name in exclude_var_names:
return False
from .utils.public import _get_varname_parts
origin_varname, _, _ = _get_varname_parts(var.name)
if origin_varname.endswith("@GRAD"):
return False
if origin_varname.startswith("learning_rate_"):
return False
if (
var.desc.type() == core.VarDesc.VarType.FEED_MINIBATCH
or var.desc.type() == core.VarDesc.VarType.FETCH_LIST
or var.desc.type() == core.VarDesc.VarType.READER
):
return False
return var.persistable
return is_valid
def _get_inference_model_path(self, dirname):
if dirname.startswith("afs:") or dirname.startswith("hdfs:"):
model_path = "./dnn_plugin"
else:
model_path = os.path.join(dirname, "dnn_plugin")
return model_path
def _ps_save_dense_params(
self, executor, dirname, scope, program, var_names=None
):
dense_map = get_the_one_recv_context(
self.context, split_dense_table=self.is_heter_ps_mode
)
send_ctx = get_the_one_send_context(
self.context,
split_dense_table=self.is_heter_ps_mode,
ep_list=self.endpoints,
)
if program is None or len(self.origin_main_programs) == 1:
program = self.origin_main_programs[0]
dense_var_names = self._pull_dense(program, scope, send_ctx, dense_map)
save_var_names = dense_var_names if var_names is None else var_names
vars = [program.global_block().var(i) for i in save_var_names]
import paddle
with paddle.static.scope_guard(scope):
paddle.static.save_vars(
executor, "./", program, vars=vars, filename=dirname
)
def _save_sparse_params(
self, executor, dirname, context, main_program, mode
):
distributed_varnames = get_sparse_tablenames(
self.origin_main_programs, True
)
values = []
model_path = self._get_inference_model_path(dirname)
for id, names in context.items():
if names[0] not in distributed_varnames:
# only save sparse param to local
try:
self._worker.recv_and_save_model(id, model_path)
except:
pass
# save sparse & distributed param on server
self._worker.save_one_model(id, dirname, mode)
values.extend(names)
# self._worker.save_all_model(dirname, mode)
return values
def _save_distributed_persistables(
self, executor, dirname, main_program=None, mode=0, **kwargs
):
"""
This function filters out all variables with `persistable==True` from the
give `main_program` and then saves these variables to the folder `dirname`
or file `filename`.
The `dirname` is used to specify the folder where persistable variables
are going to be saved. If you would like to save variables in separate
files, set `filename` None; if you would like to save all variables in a
single file, use `filename` to specify the file name.
"""
if not isinstance(executor, Executor):
raise TypeError(
"in fleet.save() function, executor must be as Executor type"
)
if main_program is None:
main_program = self.context['origin_main_program']
if isinstance(main_program, CompiledProgram):
raise TypeError(
"in fleet.save() function, main_program must be as Program type, CompiledProgram is not allowed"
)
self._worker.save_all_model(dirname, mode)
def _ps_inference_save_inference_model(
self,
executor,
dirname,
feeded_var_names,
target_vars,
main_program=None,
export_for_deployment=True,
mode=0,
):
"""
Prune the given `main_program` to build a new program especially for inference,
and then save it and all related parameters to given `dirname` by the `executor`.
"""
if not isinstance(executor, Executor):
raise TypeError(
"in fleet.save() function, executor must be as Executor type"
)
import paddle
program = (
self.origin_main_programs[0]
if main_program is None
else main_program
)
_, _, idx = get_program_by_id(self.context, id(program))
scope = self.scopes[idx]
print("save inference model scope idx:", idx)
if isinstance(program, CompiledProgram):
raise TypeError(
"in fleet.save() function, main_program must be as Program type, CompiledProgram is not allowed"
)
feed_vars = [
program.global_block().var(name) for name in feeded_var_names
]
infer_program = paddle.static.normalize_program(
program, feed_vars, target_vars
)
infer_program._copy_dist_param_info_from(program)
model_path = self._get_inference_model_path(dirname)
model_basename = "__model__"
model_basename = os.path.join(model_path, model_basename)
paddle.save(infer_program, model_basename)
sparses = get_the_one_recv_context(
self.context,
is_dense=False,
split_dense_table=self.is_heter_ps_mode,
)
sparse_names = self._save_sparse_params(
executor, dirname, sparses, main_program, mode
)
dense_map = get_the_one_recv_context(
self.context, split_dense_table=self.is_heter_ps_mode
)
send_ctx = get_the_one_send_context(
self.context,
split_dense_table=self.is_heter_ps_mode,
ep_list=self.endpoints,
)
self._pull_dense(program, scope, send_ctx, dense_map)
generate_vars = self.context[
"user_defined_strategy"
].trainer_desc_configs["stat_var_names"]
generate_vars = list(generate_vars)
remaining_vars = list(
filter(
TheOnePSRuntime.__exclude_vars(sparse_names),
infer_program.list_vars(),
)
)
for var in remaining_vars:
tensor = var.get_value(scope)
paddle.save(
tensor,
os.path.join(model_path, var.name),
use_binary_format=True,
)
def _save_cache_model(self, dirname, **kwargs):
mode = kwargs.get("mode", 1)
table_id = kwargs.get("table_id", 0)
self._worker.client_flush()
fleet.util.barrier()
cache_threshold = 0.0
if self.role_maker._is_first_worker():
cache_threshold = self._worker.get_cache_threshold(table_id)
# check cache threshold right or not
fleet.util.barrier()
if self.role_maker._is_first_worker():
self._worker.cache_shuffle(table_id, dirname, mode, cache_threshold)
fleet.util.barrier()
feasign_num = -1
if self.role_maker._is_first_worker():
feasign_num = self._worker.save_cache(table_id, dirname, mode)
fleet.util.barrier()
return feasign_num
def _save_cache_table(self, table_id, pass_id, mem_cache_key_threshold):
fleet.util.barrier()
if self.context['use_ps_gpu'] or self.role_maker._is_first_worker():
self._worker.save_cache_table(
table_id, pass_id, mem_cache_key_threshold
)
fleet.util.barrier()
def _check_save_pre_patch_done(self):
fleet.util.barrier()
if self.role_maker._is_first_worker():
self._worker.check_save_pre_patch_done()
def _load_sparse_params(self, dirname, context, main_program, mode):
distributed_varnames = get_sparse_tablenames(
self.origin_main_programs, True
)
values = []
for id, names in context.items():
if names[0] not in distributed_varnames:
# TODO: only load sparse param from local
warnings.warn("varname is not in distributed_varnames, pass")
# load sparse & distributed param on server
self._worker.load_one_table(id, dirname, mode)
values.extend(names)
return values
def _ps_inference_load_inference_model(
self, dirname, mode=0, main_program=None
):
main_program = (
self.origin_main_programs[0]
if main_program is None
else main_program
)
_, _, idx = get_program_by_id(self.context, id(main_program))
scope = self.scopes[idx]
print("load inference model scope idx:", idx)
if isinstance(main_program, CompiledProgram):
raise TypeError(
"in fleet.save() function, main_program must be as Program type, CompiledProgram is not allowed"
)
sparses = get_the_one_recv_context(
self.context,
is_dense=False,
split_dense_table=self.is_heter_ps_mode,
)
sparse_varnames = self._load_sparse_params(
dirname, sparses, main_program, mode
)
dense_map = get_the_one_recv_context(
self.context, split_dense_table=self.is_heter_ps_mode
)
send_ctx = get_the_one_send_context(
self.context,
split_dense_table=self.is_heter_ps_mode,
ep_list=self.endpoints,
)
recv_dense_varnames = []
for _, names in dense_map.items():
recv_dense_varnames.extend(names)
loaded_varnames = sparse_varnames
remaining_vars = list(
filter(
TheOnePSRuntime.__exclude_vars(loaded_varnames),
main_program.list_vars(),
)
)
model_path = self._get_inference_model_path(dirname)
import paddle
for var in remaining_vars:
if var.name not in recv_dense_varnames:
continue
tensor = paddle.load(os.path.join(model_path, var.name))
var.set_value(tensor, scope)
self._init_params(main_program, scope, send_ctx, dense_map)
def _save_one_table(self, table_id, path, mode):
fleet.util.barrier()
if self.role_maker._is_first_worker():
self._worker.save_one_model(table_id, path, mode)
fleet.util.barrier()
def _save_dense_params(self, *args, **kwargs):
fleet.util.barrier()
if self.role_maker._is_first_worker():
self._ps_save_dense_params(*args, **kwargs)
fleet.util.barrier()
def _save_persistables(self, *args, **kwargs):
fleet.util.barrier()
if self.context['use_ps_gpu'] or self.role_maker._is_first_worker():
self._save_distributed_persistables(*args, **kwargs)
fleet.util.barrier()
def _save_inference_model(self, *args, **kwargs):
fleet.util.barrier()
if self.role_maker._is_first_worker():
self._ps_inference_save_inference_model(*args, **kwargs)
fleet.util.barrier()
def _load_one_table(self, table_id, path, mode):
fleet.util.barrier()
if self.role_maker._is_first_worker():
self._worker.load_one_table(table_id, path, mode)
fleet.util.barrier()
def _load_persistables(self, path, mode):
fleet.util.barrier()
if self.context['use_ps_gpu'] or self.role_maker._is_first_worker():
self._worker.load_model(path, mode)
fleet.util.barrier()
def _load_inference_model(self, path, mode):
fleet.util.barrier()
if self.role_maker._is_first_worker():
self._ps_inference_load_inference_model(path, mode)
fleet.util.barrier()
def _set_date(self, table_id, day_id):
fleet.util.barrier()
if self.role_maker._is_first_worker():
self._worker.set_date(table_id, day_id)
fleet.util.barrier()
def _print_table_stat(self, table_id, pass_id, threshold):
fleet.util.barrier()
if self.role_maker._is_first_worker():
self._worker.print_table_stat(table_id, pass_id, threshold)
fleet.util.barrier()
def _shrink(self, threshold=None):
if threshold is not None:
warnings.warn(
"The param threshold is not used in MemorySparseTable, if you need to shrink, please set the config of accessor"
)
else:
threshold = 0
fleet.util.barrier()
if self.context['use_ps_gpu'] or self.role_maker._is_first_worker():
sparses = get_the_one_recv_context(
self.context,
is_dense=False,
split_dense_table=self.role_maker._is_heter_parameter_server_mode,
)
for id, names in sparses.items():
self._worker.shrink_sparse_table(id, threshold)
fleet.util.barrier()