2198 lines
76 KiB
C++
2198 lines
76 KiB
C++
/* Copyright (c) 2018 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. */
|
|
|
|
#include "paddle/fluid/framework/data_set.h"
|
|
|
|
#include "google/protobuf/text_format.h"
|
|
#if (defined PADDLE_WITH_DISTRIBUTE) && (defined PADDLE_WITH_PSCORE)
|
|
#include "paddle/fluid/distributed/index_dataset/index_sampler.h"
|
|
#endif
|
|
#include "paddle/common/flags.h"
|
|
#include "paddle/fluid/framework/data_feed_factory.h"
|
|
#include "paddle/fluid/framework/fleet/fleet_wrapper.h"
|
|
#include "paddle/fluid/framework/io/fs.h"
|
|
#include "paddle/fluid/framework/threadpool.h"
|
|
#include "paddle/phi/core/platform/monitor.h"
|
|
#include "paddle/phi/core/platform/timer.h"
|
|
|
|
#if defined _WIN32 || defined __APPLE__
|
|
#else
|
|
#define _LINUX
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
DEFINE_INT_STATUS(STAT_total_feasign_num_in_mem);
|
|
#else
|
|
USE_INT_STAT(STAT_total_feasign_num_in_mem);
|
|
#endif
|
|
USE_INT_STAT(STAT_epoch_finish);
|
|
COMMON_DECLARE_bool(graph_get_neighbor_id);
|
|
COMMON_DECLARE_int32(gpugraph_storage_mode);
|
|
COMMON_DECLARE_string(graph_edges_split_mode);
|
|
COMMON_DECLARE_bool(query_dest_rank_by_multi_node);
|
|
|
|
namespace paddle::framework {
|
|
|
|
// constructor
|
|
template <typename T>
|
|
DatasetImpl<T>::DatasetImpl()
|
|
: readers_(),
|
|
preload_readers_(),
|
|
input_channel_(),
|
|
input_pv_channel_(),
|
|
multi_pv_output_(),
|
|
multi_pv_consume_(),
|
|
multi_output_channel_(),
|
|
multi_consume_channel_(),
|
|
local_tables_(),
|
|
slots_shuffle_original_data_(),
|
|
pull_sparse_to_local_thread_num_(0),
|
|
filelist_(),
|
|
preload_threads_(),
|
|
current_phase_(),
|
|
consume_task_pool_(),
|
|
input_records_(),
|
|
use_slots_(),
|
|
gpu_graph_total_keys_(),
|
|
keys_vec_(),
|
|
ranks_vec_(),
|
|
keys2rank_tables_() {
|
|
VLOG(3) << "DatasetImpl<T>::DatasetImpl() constructor";
|
|
thread_num_ = 1;
|
|
trainer_num_ = 1;
|
|
channel_num_ = 1;
|
|
file_idx_ = 0;
|
|
total_fea_num_ = 0;
|
|
cur_channel_ = 0;
|
|
fleet_send_batch_size_ = 1024;
|
|
fleet_send_sleep_seconds_ = 0;
|
|
merge_by_ins_id_ = false;
|
|
merge_by_sid_ = true;
|
|
enable_pv_merge_ = false;
|
|
merge_size_ = 2;
|
|
parse_ins_id_ = false;
|
|
parse_content_ = false;
|
|
parse_logkey_ = false;
|
|
preload_thread_num_ = 0;
|
|
global_index_ = 0;
|
|
shuffle_by_uid_ = false;
|
|
parse_uid_ = false;
|
|
}
|
|
|
|
// set filelist, file_idx_ will reset to zero.
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetFileList(const std::vector<std::string>& filelist) {
|
|
VLOG(3) << "filelist size: " << filelist.size();
|
|
filelist_ = filelist;
|
|
file_idx_ = 0;
|
|
}
|
|
|
|
// set expect thread num. actually it may change
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetThreadNum(int thread_num) {
|
|
VLOG(3) << "SetThreadNum thread_num=" << thread_num;
|
|
thread_num_ = thread_num;
|
|
}
|
|
|
|
// if you run distributed, and want to do global shuffle,
|
|
// set this before global shuffle.
|
|
// be sure you call CreateReaders before SetTrainerNum
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetTrainerNum(int trainer_num) {
|
|
trainer_num_ = trainer_num;
|
|
}
|
|
|
|
// if you run distributed, and want to do global shuffle,
|
|
// set this before global shuffle.
|
|
// be sure you call CreateReaders before SetFleetSendBatchSize
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetFleetSendBatchSize(int64_t size) {
|
|
fleet_send_batch_size_ = size;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetHdfsConfig(const std::string& fs_name,
|
|
const std::string& fs_ugi) {
|
|
fs_name_ = fs_name;
|
|
fs_ugi_ = fs_ugi;
|
|
std::string cmd = std::string("$HADOOP_HOME/bin/hadoop fs");
|
|
cmd += " -D fs.default.name=" + fs_name;
|
|
cmd += " -D hadoop.job.ugi=" + fs_ugi;
|
|
cmd += " -Ddfs.client.block.write.retries=15 -Ddfs.rpc.timeout=500000";
|
|
paddle::framework::dataset_hdfs_set_command(cmd);
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetDownloadCmd(const std::string& download_cmd) {
|
|
paddle::framework::set_download_command(download_cmd);
|
|
}
|
|
|
|
template <typename T>
|
|
std::string DatasetImpl<T>::GetDownloadCmd() {
|
|
return paddle::framework::download_cmd();
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetDataFeedDesc(const std::string& data_feed_desc_str) {
|
|
google::protobuf::TextFormat::ParseFromString(data_feed_desc_str,
|
|
&data_feed_desc_);
|
|
}
|
|
|
|
template <typename T>
|
|
std::vector<std::string> DatasetImpl<T>::GetSlots() {
|
|
auto multi_slot_desc = data_feed_desc_.multi_slot_desc();
|
|
use_slots_.clear();
|
|
for (int i = 0; i < multi_slot_desc.slots_size(); ++i) {
|
|
const auto& slot = multi_slot_desc.slots(i);
|
|
if (slot.type() == "uint64" || slot.type() == "uint32") {
|
|
use_slots_.push_back(slot.name());
|
|
}
|
|
}
|
|
std::cout << "dataset use slots: ";
|
|
for (auto const& s : use_slots_) {
|
|
std::cout << s << " | ";
|
|
}
|
|
std::cout << " end " << std::endl;
|
|
return use_slots_;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetChannelNum(int channel_num) {
|
|
channel_num_ = channel_num;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetParseInsId(bool parse_ins_id) {
|
|
parse_ins_id_ = parse_ins_id;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetParseContent(bool parse_content) {
|
|
parse_content_ = parse_content;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetParseLogKey(bool parse_logkey) {
|
|
parse_logkey_ = parse_logkey;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetMergeByInsId(int merge_size) {
|
|
merge_by_ins_id_ = true;
|
|
parse_ins_id_ = true;
|
|
merge_size_ = merge_size;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetMergeBySid(bool is_merge) {
|
|
merge_by_sid_ = is_merge;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetShuffleByUid(bool enable_shuffle_uid) {
|
|
shuffle_by_uid_ = enable_shuffle_uid;
|
|
parse_uid_ = true;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetEnablePvMerge(bool enable_pv_merge) {
|
|
enable_pv_merge_ = enable_pv_merge;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetGenerateUniqueFeasign(bool gen_uni_feasigns) {
|
|
gen_uni_feasigns_ = gen_uni_feasigns;
|
|
VLOG(3) << "Set generate unique feasigns: " << gen_uni_feasigns;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetFeaEval(bool fea_eval, int record_candidate_size) {
|
|
slots_shuffle_fea_eval_ = fea_eval;
|
|
slots_shuffle_rclist_.ReSize(record_candidate_size);
|
|
VLOG(3) << "SetFeaEval fea eval mode: " << fea_eval
|
|
<< " with record candidate size: " << record_candidate_size;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetGpuGraphMode(int is_graph_mode) {
|
|
gpu_graph_mode_ = is_graph_mode;
|
|
}
|
|
|
|
template <typename T>
|
|
int DatasetImpl<T>::GetGpuGraphMode() {
|
|
return gpu_graph_mode_;
|
|
}
|
|
|
|
template <typename T>
|
|
std::vector<paddle::framework::DataFeed*> DatasetImpl<T>::GetReaders() {
|
|
std::vector<paddle::framework::DataFeed*> ret;
|
|
ret.reserve(readers_.size());
|
|
for (auto const& i : readers_) {
|
|
ret.push_back(i.get());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::CreateChannel() {
|
|
if (input_channel_ == nullptr) {
|
|
input_channel_ = paddle::framework::MakeChannel<T>();
|
|
}
|
|
if (multi_output_channel_.empty()) {
|
|
multi_output_channel_.reserve(channel_num_);
|
|
for (int i = 0; i < channel_num_; ++i) {
|
|
multi_output_channel_.push_back(paddle::framework::MakeChannel<T>());
|
|
}
|
|
}
|
|
if (multi_consume_channel_.empty()) {
|
|
multi_consume_channel_.reserve(channel_num_);
|
|
for (int i = 0; i < channel_num_; ++i) {
|
|
multi_consume_channel_.push_back(paddle::framework::MakeChannel<T>());
|
|
}
|
|
}
|
|
if (input_pv_channel_ == nullptr) {
|
|
input_pv_channel_ = paddle::framework::MakeChannel<PvInstance>();
|
|
}
|
|
if (multi_pv_output_.empty()) {
|
|
multi_pv_output_.reserve(channel_num_);
|
|
for (int i = 0; i < channel_num_; ++i) {
|
|
multi_pv_output_.push_back(paddle::framework::MakeChannel<PvInstance>());
|
|
}
|
|
}
|
|
if (multi_pv_consume_.empty()) {
|
|
multi_pv_consume_.reserve(channel_num_);
|
|
for (int i = 0; i < channel_num_; ++i) {
|
|
multi_pv_consume_.push_back(paddle::framework::MakeChannel<PvInstance>());
|
|
}
|
|
}
|
|
}
|
|
|
|
// if sent message between workers, should first call this function
|
|
template <typename T>
|
|
void DatasetImpl<T>::RegisterClientToClientMsgHandler() {
|
|
#ifdef PADDLE_WITH_PSCORE
|
|
auto fleet_ptr = distributed::FleetWrapper::GetInstance();
|
|
#else
|
|
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
|
#endif
|
|
VLOG(1) << "RegisterClientToClientMsgHandler";
|
|
fleet_ptr->RegisterClientToClientMsgHandler(
|
|
0, [this](int msg_type, int client_id, const std::string& msg) -> int {
|
|
return this->ReceiveFromClient(msg_type, client_id, msg);
|
|
});
|
|
VLOG(1) << "RegisterClientToClientMsgHandler done";
|
|
}
|
|
static void compute_left_batch_num(const int ins_num,
|
|
const int thread_num,
|
|
std::vector<std::pair<int, int>>* offset,
|
|
const int start_pos) {
|
|
int cur_pos = start_pos;
|
|
int batch_size = ins_num / thread_num;
|
|
int left_num = ins_num % thread_num;
|
|
for (int i = 0; i < thread_num; ++i) {
|
|
int batch_num_size = batch_size;
|
|
if (i == 0) {
|
|
batch_num_size = batch_num_size + left_num;
|
|
}
|
|
offset->push_back(std::make_pair(cur_pos, batch_num_size));
|
|
cur_pos += batch_num_size;
|
|
}
|
|
}
|
|
|
|
static void compute_batch_num(const int64_t ins_num,
|
|
const int batch_size,
|
|
const int thread_num,
|
|
std::vector<std::pair<int, int>>* offset) {
|
|
int thread_batch_num = batch_size * thread_num;
|
|
// less data
|
|
if (static_cast<int64_t>(thread_batch_num) > ins_num) {
|
|
compute_left_batch_num(static_cast<int>(ins_num), thread_num, offset, 0);
|
|
return;
|
|
}
|
|
|
|
int cur_pos = 0;
|
|
int offset_num = static_cast<int>(ins_num / thread_batch_num) * thread_num;
|
|
int left_ins_num = static_cast<int>(ins_num % thread_batch_num);
|
|
if (left_ins_num > 0 && left_ins_num < thread_num) {
|
|
offset_num = offset_num - thread_num;
|
|
left_ins_num = left_ins_num + thread_batch_num;
|
|
for (int i = 0; i < offset_num; ++i) {
|
|
offset->push_back(std::make_pair(cur_pos, batch_size));
|
|
cur_pos += batch_size;
|
|
}
|
|
// split data to thread avg two rounds
|
|
compute_left_batch_num(left_ins_num, thread_num * 2, offset, cur_pos);
|
|
} else {
|
|
for (int i = 0; i < offset_num; ++i) {
|
|
offset->push_back(std::make_pair(cur_pos, batch_size));
|
|
cur_pos += batch_size;
|
|
}
|
|
if (left_ins_num > 0) {
|
|
compute_left_batch_num(left_ins_num, thread_num, offset, cur_pos);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int compute_thread_batch_nccl(
|
|
const int thr_num,
|
|
const int64_t total_instance_num,
|
|
const int minibatch_size,
|
|
std::vector<std::pair<int, int>>* nccl_offsets) {
|
|
int thread_avg_batch_num = 0;
|
|
if (total_instance_num < static_cast<int64_t>(thr_num)) {
|
|
LOG(WARNING) << "compute_thread_batch_nccl total ins num:["
|
|
<< total_instance_num << "], less thread num:[" << thr_num
|
|
<< "]";
|
|
return thread_avg_batch_num;
|
|
}
|
|
|
|
auto& offset = (*nccl_offsets);
|
|
// split data avg by thread num
|
|
compute_batch_num(total_instance_num, minibatch_size, thr_num, &offset);
|
|
thread_avg_batch_num = static_cast<int>(offset.size() / thr_num); // NOLINT
|
|
#ifdef PADDLE_WITH_GLOO
|
|
auto gloo_wrapper = paddle::framework::GlooWrapper::GetInstance();
|
|
if (gloo_wrapper->Size() > 1) {
|
|
if (!gloo_wrapper->IsInitialized()) {
|
|
VLOG(0) << "GLOO is not inited";
|
|
gloo_wrapper->Init();
|
|
}
|
|
// adjust batch num per thread for NCCL
|
|
std::vector<int> thread_avg_batch_num_vec(1, thread_avg_batch_num);
|
|
std::vector<int64_t> total_instance_num_vec(1, total_instance_num);
|
|
auto thread_max_batch_num_vec =
|
|
gloo_wrapper->AllReduce(thread_avg_batch_num_vec, "max");
|
|
auto sum_total_ins_num_vec =
|
|
gloo_wrapper->AllReduce(total_instance_num_vec, "sum");
|
|
int thread_max_batch_num = thread_max_batch_num_vec[0];
|
|
int64_t sum_total_ins_num = sum_total_ins_num_vec[0];
|
|
int diff_batch_num = thread_max_batch_num - thread_avg_batch_num;
|
|
VLOG(3) << "diff batch num: " << diff_batch_num
|
|
<< " thread max batch num: " << thread_max_batch_num
|
|
<< " thread avg batch num: " << thread_avg_batch_num;
|
|
if (diff_batch_num == 0) {
|
|
LOG(WARNING) << "total sum ins " << sum_total_ins_num << ", thread_num "
|
|
<< thr_num << ", ins num " << total_instance_num
|
|
<< ", batch num " << offset.size()
|
|
<< ", thread avg batch num " << thread_avg_batch_num;
|
|
return thread_avg_batch_num;
|
|
}
|
|
|
|
int need_ins_num = thread_max_batch_num * thr_num;
|
|
// data is too less
|
|
if ((int64_t)need_ins_num > total_instance_num) {
|
|
PADDLE_THROW(common::errors::InvalidArgument(
|
|
"error instance num:[%d] less need ins num:[%d]",
|
|
total_instance_num,
|
|
need_ins_num));
|
|
return thread_avg_batch_num;
|
|
}
|
|
|
|
int need_batch_num = (diff_batch_num + 1) * thr_num;
|
|
int offset_split_index = static_cast<int>(offset.size() - thr_num);
|
|
int split_left_num = total_instance_num - offset[offset_split_index].first;
|
|
while (split_left_num < need_batch_num) {
|
|
need_batch_num += thr_num;
|
|
offset_split_index -= thr_num;
|
|
split_left_num = total_instance_num - offset[offset_split_index].first;
|
|
}
|
|
int split_start = offset[offset_split_index].first;
|
|
offset.resize(offset_split_index);
|
|
compute_left_batch_num(
|
|
split_left_num, need_batch_num, &offset, split_start);
|
|
LOG(WARNING) << "total sum ins " << sum_total_ins_num << ", thread_num "
|
|
<< thr_num << ", ins num " << total_instance_num
|
|
<< ", batch num " << offset.size() << ", thread avg batch num "
|
|
<< thread_avg_batch_num << ", thread max batch num "
|
|
<< thread_max_batch_num
|
|
<< ", need batch num: " << (need_batch_num / thr_num)
|
|
<< "split begin (" << split_start << ")" << split_start
|
|
<< ", num " << split_left_num;
|
|
thread_avg_batch_num = thread_max_batch_num;
|
|
} else {
|
|
LOG(WARNING) << "thread_num " << thr_num << ", ins num "
|
|
<< total_instance_num << ", batch num " << offset.size()
|
|
<< ", thread avg batch num " << thread_avg_batch_num;
|
|
}
|
|
#else
|
|
PADDLE_THROW(common::errors::Unavailable(
|
|
"dataset compute nccl batch number need compile with GLOO"));
|
|
#endif
|
|
return thread_avg_batch_num;
|
|
}
|
|
|
|
void MultiSlotDataset::PrepareTrain() {
|
|
#ifdef PADDLE_WITH_GLOO
|
|
if (enable_heterps_) {
|
|
if (input_records_.empty() && input_channel_ != nullptr &&
|
|
input_channel_->Size() != 0) {
|
|
input_channel_->ReadAll(input_records_);
|
|
VLOG(3) << "read from channel to records with records size: "
|
|
<< input_records_.size();
|
|
}
|
|
VLOG(3) << "input records size: " << input_records_.size();
|
|
int64_t total_ins_num = input_records_.size();
|
|
std::vector<std::pair<int, int>> offset;
|
|
int default_batch_size =
|
|
reinterpret_cast<MultiSlotInMemoryDataFeed*>(readers_[0].get())
|
|
->GetDefaultBatchSize();
|
|
VLOG(3) << "thread_num: " << thread_num_
|
|
<< " memory size: " << total_ins_num
|
|
<< " default batch_size: " << default_batch_size;
|
|
compute_thread_batch_nccl(
|
|
thread_num_, total_ins_num, default_batch_size, &offset);
|
|
VLOG(3) << "offset size: " << offset.size();
|
|
for (int i = 0; i < thread_num_; i++) {
|
|
reinterpret_cast<MultiSlotInMemoryDataFeed*>(readers_[i].get())
|
|
->SetRecord(&input_records_[0]);
|
|
}
|
|
for (size_t i = 0; i < offset.size(); i++) {
|
|
reinterpret_cast<MultiSlotInMemoryDataFeed*>(
|
|
readers_[i % thread_num_].get())
|
|
->AddBatchOffset(offset[i]);
|
|
}
|
|
}
|
|
#else
|
|
PADDLE_THROW(common::errors::Unavailable(
|
|
"dataset set heterps need compile with GLOO"));
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
inline std::vector<std::shared_ptr<phi::ThreadPool>>& GetReadThreadPool(
|
|
int thread_num) {
|
|
static std::vector<std::shared_ptr<phi::ThreadPool>> thread_pools;
|
|
if (!thread_pools.empty()) {
|
|
return thread_pools;
|
|
}
|
|
thread_pools.resize(thread_num);
|
|
for (int i = 0; i < thread_num; ++i) {
|
|
thread_pools[i].reset(new phi::ThreadPool(1));
|
|
}
|
|
return thread_pools;
|
|
}
|
|
|
|
// load data into memory, Dataset hold this memory,
|
|
// which will later be fed into readers' channel
|
|
template <typename T>
|
|
void DatasetImpl<T>::LoadIntoMemory() {
|
|
VLOG(3) << "DatasetImpl<T>::LoadIntoMemory() begin";
|
|
platform::Timer timeline;
|
|
timeline.Start();
|
|
if (gpu_graph_mode_) {
|
|
VLOG(1) << "in gpu_graph_mode";
|
|
#if defined(PADDLE_WITH_PSCORE) && defined(PADDLE_WITH_HETERPS)
|
|
std::vector<std::future<void>> wait_futures;
|
|
auto pool = GetReadThreadPool(thread_num_);
|
|
for (size_t i = 0; i < readers_.size(); i++) {
|
|
readers_[i]->SetGpuGraphMode(gpu_graph_mode_);
|
|
}
|
|
|
|
if (STAT_GET(STAT_epoch_finish) == 1) {
|
|
VLOG(0) << "get epoch finish true";
|
|
STAT_RESET(STAT_epoch_finish, 0);
|
|
for (size_t i = 0; i < readers_.size(); i++) {
|
|
readers_[i]->ResetPathNum();
|
|
readers_[i]->ResetEpochFinish();
|
|
}
|
|
}
|
|
|
|
for (int64_t i = 0; i < thread_num_; ++i) {
|
|
wait_futures.emplace_back(
|
|
pool[i]->Run([this, i]() { readers_[i]->DoWalkandSage(); }));
|
|
}
|
|
for (auto& th : wait_futures) {
|
|
th.get();
|
|
}
|
|
wait_futures.clear();
|
|
|
|
uint64_t node_num = 0;
|
|
std::vector<uint64_t> offsets;
|
|
offsets.resize(thread_num_);
|
|
|
|
for (int i = 0; i < thread_num_; i++) {
|
|
auto& host_vec = (*readers_[i]->GetHostVec());
|
|
offsets[i] = node_num;
|
|
node_num += host_vec.size();
|
|
}
|
|
gpu_graph_total_keys_.resize(node_num + 1);
|
|
for (int i = 0; i < thread_num_; i++) {
|
|
uint64_t off = offsets[i];
|
|
wait_futures.emplace_back(pool[i]->Run([this, i, off]() {
|
|
auto& host_vec = (*readers_[i]->GetHostVec());
|
|
for (size_t j = 0; j < host_vec.size(); j++) {
|
|
gpu_graph_total_keys_[off + j] = host_vec[j];
|
|
}
|
|
if (FLAGS_gpugraph_storage_mode != GpuGraphStorageMode::WHOLE_HBM) {
|
|
readers_[i]->clear_gpu_mem();
|
|
}
|
|
}));
|
|
}
|
|
for (auto& th : wait_futures) {
|
|
th.get();
|
|
}
|
|
wait_futures.clear();
|
|
|
|
uint64_t zerokey = 0;
|
|
gpu_graph_total_keys_.emplace_back(zerokey);
|
|
VLOG(0) << "add zero key in multi node";
|
|
|
|
// for fennel mode
|
|
keys_vec_.resize(thread_num_);
|
|
ranks_vec_.resize(thread_num_);
|
|
keys2rank_tables_.resize(thread_num_);
|
|
if (FLAGS_graph_edges_split_mode == "fennel" ||
|
|
FLAGS_query_dest_rank_by_multi_node) {
|
|
for (int i = 0; i < thread_num_; i++) {
|
|
keys_vec_[i] = readers_[i]->GetHostVec();
|
|
ranks_vec_[i] = readers_[i]->GetHostRanks();
|
|
keys2rank_tables_[i] = readers_[i]->GetKeys2RankTable();
|
|
}
|
|
keys_vec_[0]->push_back(zerokey);
|
|
if (readers_[0]->IsTrainMode() || readers_[0]->GetSageMode()) {
|
|
ranks_vec_[0]->push_back(0);
|
|
}
|
|
}
|
|
|
|
if (GetEpochFinish() == true) {
|
|
VLOG(0) << "epoch finish, set stat and clear sample stat!";
|
|
STAT_RESET(STAT_epoch_finish, 1);
|
|
for (size_t i = 0; i < readers_.size(); i++) {
|
|
readers_[i]->ClearSampleState();
|
|
}
|
|
}
|
|
|
|
VLOG(1) << "end add edge into gpu_graph_total_keys_ size[" << node_num
|
|
<< "]";
|
|
#endif
|
|
} else {
|
|
std::vector<std::thread> load_threads;
|
|
for (int64_t i = 0; i < thread_num_; ++i) {
|
|
load_threads.emplace_back(&paddle::framework::DataFeed::LoadIntoMemory,
|
|
readers_[i].get());
|
|
}
|
|
for (std::thread& t : load_threads) {
|
|
t.join();
|
|
}
|
|
}
|
|
input_channel_->Close();
|
|
int64_t in_chan_size = input_channel_->Size();
|
|
input_channel_->SetBlockSize(in_chan_size / thread_num_ + 1);
|
|
|
|
timeline.Pause();
|
|
VLOG(3) << "DatasetImpl<T>::LoadIntoMemory() end"
|
|
<< ", memory data size=" << input_channel_->Size()
|
|
<< ", cost time=" << timeline.ElapsedSec() << " seconds";
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::PreLoadIntoMemory() {
|
|
VLOG(3) << "DatasetImpl<T>::PreLoadIntoMemory() begin";
|
|
if (preload_thread_num_ != 0) {
|
|
PADDLE_ENFORCE_EQ(static_cast<size_t>(preload_thread_num_),
|
|
preload_readers_.size(),
|
|
common::errors::InvalidArgument(
|
|
"Preload thread number (%d) does not "
|
|
"match the size of preload readers (%d).",
|
|
preload_thread_num_,
|
|
preload_readers_.size()));
|
|
preload_threads_.clear();
|
|
for (int64_t i = 0; i < preload_thread_num_; ++i) {
|
|
preload_threads_.emplace_back(
|
|
&paddle::framework::DataFeed::LoadIntoMemory,
|
|
preload_readers_[i].get());
|
|
}
|
|
} else {
|
|
PADDLE_ENFORCE_EQ(
|
|
static_cast<size_t>(thread_num_),
|
|
readers_.size(),
|
|
common::errors::InvalidArgument(
|
|
"Thread number (%d) does not match the size of readers (%d).",
|
|
thread_num_,
|
|
readers_.size()));
|
|
preload_threads_.clear();
|
|
for (int64_t i = 0; i < thread_num_; ++i) {
|
|
preload_threads_.emplace_back(
|
|
&paddle::framework::DataFeed::LoadIntoMemory, readers_[i].get());
|
|
}
|
|
}
|
|
VLOG(3) << "DatasetImpl<T>::PreLoadIntoMemory() end";
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::WaitPreLoadDone() {
|
|
VLOG(3) << "DatasetImpl<T>::WaitPreLoadDone() begin";
|
|
for (std::thread& t : preload_threads_) {
|
|
t.join();
|
|
}
|
|
input_channel_->Close();
|
|
int64_t in_chan_size = input_channel_->Size();
|
|
input_channel_->SetBlockSize(in_chan_size / thread_num_ + 1);
|
|
VLOG(3) << "DatasetImpl<T>::WaitPreLoadDone() end";
|
|
}
|
|
|
|
// release memory data
|
|
template <typename T>
|
|
void DatasetImpl<T>::ReleaseMemory() {
|
|
release_thread_ = new std::thread(&DatasetImpl<T>::ReleaseMemoryFun, this);
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::ReleaseMemoryFun() {
|
|
VLOG(3) << "DatasetImpl<T>::ReleaseMemory() begin";
|
|
if (input_channel_) {
|
|
input_channel_->Clear();
|
|
input_channel_ = nullptr;
|
|
}
|
|
for (size_t i = 0; i < multi_output_channel_.size(); ++i) {
|
|
if (!multi_output_channel_[i]) {
|
|
continue;
|
|
}
|
|
multi_output_channel_[i]->Clear();
|
|
multi_output_channel_[i] = nullptr;
|
|
}
|
|
std::vector<paddle::framework::Channel<T>>().swap(multi_output_channel_);
|
|
for (size_t i = 0; i < multi_consume_channel_.size(); ++i) {
|
|
if (!multi_consume_channel_[i]) {
|
|
continue;
|
|
}
|
|
multi_consume_channel_[i]->Clear();
|
|
multi_consume_channel_[i] = nullptr;
|
|
}
|
|
std::vector<paddle::framework::Channel<T>>().swap(multi_consume_channel_);
|
|
if (input_pv_channel_) {
|
|
input_pv_channel_->Clear();
|
|
input_pv_channel_ = nullptr;
|
|
}
|
|
for (auto& pv_output : multi_pv_output_) {
|
|
if (!pv_output) {
|
|
continue;
|
|
}
|
|
pv_output->Clear();
|
|
pv_output = nullptr;
|
|
}
|
|
std::vector<paddle::framework::Channel<PvInstance>>().swap(multi_pv_output_);
|
|
for (auto& pv_consume : multi_pv_consume_) {
|
|
if (!pv_consume) {
|
|
continue;
|
|
}
|
|
pv_consume->Clear();
|
|
pv_consume = nullptr;
|
|
}
|
|
if (enable_heterps_) {
|
|
input_records_.clear();
|
|
input_records_.shrink_to_fit();
|
|
std::vector<T>().swap(input_records_);
|
|
VLOG(3) << "release heterps input records records size: "
|
|
<< input_records_.size();
|
|
}
|
|
std::vector<paddle::framework::Channel<PvInstance>>().swap(multi_pv_consume_);
|
|
|
|
std::vector<std::shared_ptr<paddle::framework::DataFeed>>().swap(readers_);
|
|
input_records_.clear();
|
|
std::vector<T>().swap(input_records_);
|
|
std::vector<T>().swap(slots_shuffle_original_data_);
|
|
VLOG(3) << "DatasetImpl<T>::ReleaseMemory() end";
|
|
VLOG(3) << "total_feasign_num_(" << STAT_GET(STAT_total_feasign_num_in_mem)
|
|
<< ") - current_fea_num_(" << total_fea_num_ << ") = ("
|
|
<< STAT_GET(STAT_total_feasign_num_in_mem) - total_fea_num_
|
|
<< ")"; // For Debug
|
|
STAT_SUB(STAT_total_feasign_num_in_mem, total_fea_num_);
|
|
}
|
|
|
|
// do local shuffle
|
|
template <typename T>
|
|
void DatasetImpl<T>::LocalShuffle() {
|
|
VLOG(3) << "DatasetImpl<T>::LocalShuffle() begin";
|
|
platform::Timer timeline;
|
|
timeline.Start();
|
|
|
|
if (!input_channel_ || input_channel_->Size() == 0) {
|
|
VLOG(3) << "DatasetImpl<T>::LocalShuffle() end, no data to shuffle";
|
|
return;
|
|
}
|
|
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
|
input_channel_->Close();
|
|
std::vector<T> data;
|
|
input_channel_->ReadAll(data);
|
|
std::shuffle(data.begin(), data.end(), fleet_ptr->LocalRandomEngine());
|
|
input_channel_->Open();
|
|
input_channel_->Write(std::move(data));
|
|
data.clear();
|
|
data.shrink_to_fit();
|
|
input_channel_->Close();
|
|
|
|
timeline.Pause();
|
|
VLOG(3) << "DatasetImpl<T>::LocalShuffle() end, cost time="
|
|
<< timeline.ElapsedSec() << " seconds";
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::DumpWalkPath(std::string dump_path, size_t dump_rate) {
|
|
VLOG(3) << "DatasetImpl<T>::DumpWalkPath() begin";
|
|
#if defined(PADDLE_WITH_PSCORE) && defined(PADDLE_WITH_HETERPS)
|
|
std::vector<std::thread> dump_threads;
|
|
if (gpu_graph_mode_) {
|
|
for (int64_t i = 0; i < thread_num_; ++i) {
|
|
dump_threads.push_back(
|
|
std::thread(&paddle::framework::DataFeed::DumpWalkPath,
|
|
readers_[i].get(),
|
|
dump_path,
|
|
dump_rate));
|
|
}
|
|
for (std::thread& t : dump_threads) {
|
|
t.join();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::DumpSampleNeighbors(std::string dump_path) {
|
|
VLOG(1) << "DatasetImpl<T>::DumpSampleNeighbors() begin";
|
|
#if defined(PADDLE_WITH_HETERPS)
|
|
std::vector<std::thread> dump_threads;
|
|
if (gpu_graph_mode_) {
|
|
for (int64_t i = 0; i < thread_num_; ++i) {
|
|
dump_threads.push_back(
|
|
std::thread(&paddle::framework::DataFeed::DumpSampleNeighbors,
|
|
readers_[i].get(),
|
|
dump_path));
|
|
}
|
|
for (std::thread& t : dump_threads) {
|
|
t.join();
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// do tdm sample
|
|
void MultiSlotDataset::TDMSample(const std::string tree_name,
|
|
const std::string tree_path,
|
|
const std::vector<uint16_t> tdm_layer_counts,
|
|
const uint16_t start_sample_layer,
|
|
const bool with_hierarchy,
|
|
const uint16_t seed_,
|
|
const uint16_t sample_slot) {
|
|
#if (defined PADDLE_WITH_DISTRIBUTE) && (defined PADDLE_WITH_PSCORE)
|
|
// init tdm tree
|
|
auto wrapper_ptr = paddle::distributed::IndexWrapper::GetInstance();
|
|
wrapper_ptr->insert_tree_index(tree_name, tree_path);
|
|
auto tree_ptr = wrapper_ptr->get_tree_index(tree_name);
|
|
auto _layer_wise_sample = paddle::distributed::LayerWiseSampler(tree_name);
|
|
_layer_wise_sample.init_layerwise_conf(
|
|
tdm_layer_counts, start_sample_layer, seed_);
|
|
|
|
VLOG(0) << "DatasetImpl<T>::Sample() begin";
|
|
platform::Timer timeline;
|
|
timeline.Start();
|
|
|
|
std::vector<std::vector<Record>> data;
|
|
std::vector<std::vector<Record>> sample_results;
|
|
if (!input_channel_ || input_channel_->Size() == 0) {
|
|
for (size_t i = 0; i < multi_output_channel_.size(); ++i) {
|
|
std::vector<Record> tmp_data;
|
|
data.push_back(tmp_data);
|
|
if (!multi_output_channel_[i] || multi_output_channel_[i]->Size() == 0) {
|
|
continue;
|
|
}
|
|
multi_output_channel_[i]->Close();
|
|
multi_output_channel_[i]->ReadAll(data[i]);
|
|
}
|
|
} else {
|
|
input_channel_->Close();
|
|
std::vector<Record> tmp_data;
|
|
data.push_back(tmp_data);
|
|
input_channel_->ReadAll(data[data.size() - 1]);
|
|
}
|
|
|
|
VLOG(1) << "finish read src data, data.size = " << data.size()
|
|
<< "; details: ";
|
|
auto fleet_ptr = FleetWrapper::GetInstance();
|
|
for (unsigned int i = 0; i < data.size(); i++) {
|
|
VLOG(1) << "data[" << i << "]: size = " << data[i].size();
|
|
std::vector<Record> tmp_results;
|
|
_layer_wise_sample.sample_from_dataset(sample_slot, &data[i], &tmp_results);
|
|
VLOG(1) << "sample_results(" << sample_slot << ") = " << tmp_results.size();
|
|
VLOG(0) << "start to put sample in vector!";
|
|
// sample_results.push_back(tmp_results);
|
|
for (auto& tmp_result : tmp_results) {
|
|
std::vector<Record> tmp_vec;
|
|
tmp_vec.emplace_back(tmp_result);
|
|
sample_results.emplace_back(tmp_vec);
|
|
}
|
|
VLOG(0) << "finish to put sample in vector!";
|
|
}
|
|
|
|
auto output_channel_num = multi_output_channel_.size();
|
|
for (auto& sample_result : sample_results) {
|
|
auto output_idx = fleet_ptr->LocalRandomEngine()() % output_channel_num;
|
|
multi_output_channel_[output_idx]->Open();
|
|
// vector?
|
|
multi_output_channel_[output_idx]->Write(std::move(sample_result));
|
|
}
|
|
|
|
data.clear();
|
|
sample_results.clear();
|
|
data.shrink_to_fit();
|
|
sample_results.shrink_to_fit();
|
|
|
|
timeline.Pause();
|
|
VLOG(0) << "DatasetImpl<T>::Sample() end, cost time=" << timeline.ElapsedSec()
|
|
<< " seconds";
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
void MultiSlotDataset::GlobalShuffle(int thread_num) {
|
|
VLOG(3) << "MultiSlotDataset::GlobalShuffle() begin";
|
|
platform::Timer timeline;
|
|
timeline.Start();
|
|
#ifdef PADDLE_WITH_PSCORE
|
|
auto fleet_ptr = distributed::FleetWrapper::GetInstance();
|
|
#else
|
|
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
|
#endif
|
|
|
|
if (!input_channel_ || input_channel_->Size() == 0) {
|
|
VLOG(3) << "MultiSlotDataset::GlobalShuffle() end, no data to shuffle";
|
|
return;
|
|
}
|
|
|
|
// local shuffle
|
|
input_channel_->Close();
|
|
std::vector<Record> data;
|
|
input_channel_->ReadAll(data);
|
|
std::shuffle(data.begin(), data.end(), fleet_ptr->LocalRandomEngine());
|
|
input_channel_->Open();
|
|
input_channel_->Write(std::move(data));
|
|
data.clear();
|
|
data.shrink_to_fit();
|
|
|
|
input_channel_->Close();
|
|
input_channel_->SetBlockSize(fleet_send_batch_size_);
|
|
VLOG(3) << "MultiSlotDataset::GlobalShuffle() input_channel_ size "
|
|
<< input_channel_->Size();
|
|
|
|
auto get_client_id = [this, fleet_ptr](const Record& data) -> size_t {
|
|
if (this->merge_by_ins_id_) {
|
|
return XXH64(data.ins_id_.data(), data.ins_id_.length(), 0) %
|
|
this->trainer_num_;
|
|
} else if (this->shuffle_by_uid_) {
|
|
return XXH64(data.uid_.data(), data.uid_.length(), 0) %
|
|
this->trainer_num_;
|
|
} else {
|
|
return fleet_ptr->LocalRandomEngine()() % this->trainer_num_;
|
|
}
|
|
};
|
|
|
|
auto global_shuffle_func = [this, get_client_id]() {
|
|
#ifdef PADDLE_WITH_PSCORE
|
|
auto fleet_ptr = distributed::FleetWrapper::GetInstance();
|
|
#else
|
|
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
|
#endif
|
|
// auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
|
std::vector<Record> data;
|
|
while (this->input_channel_->Read(data)) {
|
|
std::vector<paddle::framework::BinaryArchive> ars(this->trainer_num_);
|
|
for (auto& t : data) {
|
|
auto client_id = get_client_id(t);
|
|
ars[client_id] << t;
|
|
}
|
|
std::vector<std::future<int32_t>> total_status;
|
|
std::vector<int> send_index(this->trainer_num_);
|
|
for (int i = 0; i < this->trainer_num_; ++i) {
|
|
send_index[i] = i;
|
|
}
|
|
std::shuffle(
|
|
send_index.begin(), send_index.end(), fleet_ptr->LocalRandomEngine());
|
|
for (int index = 0; index < this->trainer_num_; ++index) {
|
|
int i = send_index[index];
|
|
if (ars[i].Length() == 0) {
|
|
continue;
|
|
}
|
|
std::string msg(ars[i].Buffer(), ars[i].Length());
|
|
auto ret = fleet_ptr->SendClientToClientMsg(0, i, msg);
|
|
total_status.push_back(std::move(ret));
|
|
}
|
|
for (auto& t : total_status) {
|
|
t.wait();
|
|
}
|
|
ars.clear();
|
|
ars.shrink_to_fit();
|
|
data.clear();
|
|
data.shrink_to_fit();
|
|
// currently we find bottleneck is server not able to handle large data
|
|
// in time, so we can remove this sleep and set fleet_send_batch_size to
|
|
// 1024, and set server thread to 24.
|
|
if (fleet_send_sleep_seconds_ != 0) {
|
|
sleep(this->fleet_send_sleep_seconds_);
|
|
}
|
|
}
|
|
};
|
|
|
|
std::vector<std::thread> global_shuffle_threads;
|
|
if (thread_num == -1) {
|
|
thread_num = thread_num_;
|
|
}
|
|
VLOG(3) << "start global shuffle threads, num = " << thread_num;
|
|
for (int i = 0; i < thread_num; ++i) {
|
|
global_shuffle_threads.emplace_back(global_shuffle_func);
|
|
}
|
|
for (std::thread& t : global_shuffle_threads) {
|
|
t.join();
|
|
}
|
|
global_shuffle_threads.clear();
|
|
global_shuffle_threads.shrink_to_fit();
|
|
input_channel_->Clear();
|
|
timeline.Pause();
|
|
VLOG(3) << "DatasetImpl<T>::GlobalShuffle() end, cost time="
|
|
<< timeline.ElapsedSec() << " seconds";
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::DynamicAdjustChannelNum(int channel_num,
|
|
bool discard_remaining_ins) {
|
|
if (channel_num_ == channel_num) {
|
|
VLOG(3) << "DatasetImpl<T>::DynamicAdjustChannelNum channel_num_="
|
|
<< channel_num_ << ", channel_num_=channel_num, no need to adjust";
|
|
return;
|
|
}
|
|
VLOG(3) << "adjust channel num from " << channel_num_ << " to "
|
|
<< channel_num;
|
|
channel_num_ = channel_num;
|
|
std::vector<paddle::framework::Channel<T>>* origin_channels = nullptr;
|
|
std::vector<paddle::framework::Channel<T>>* other_channels = nullptr;
|
|
std::vector<paddle::framework::Channel<PvInstance>>* origin_pv_channels =
|
|
nullptr;
|
|
std::vector<paddle::framework::Channel<PvInstance>>* other_pv_channels =
|
|
nullptr;
|
|
|
|
// find out which channel (output or consume) has data
|
|
int cur_channel = 0;
|
|
uint64_t output_channels_data_size = 0;
|
|
uint64_t consume_channels_data_size = 0;
|
|
PADDLE_ENFORCE_EQ(multi_output_channel_.size(),
|
|
multi_consume_channel_.size(),
|
|
common::errors::InvalidArgument(
|
|
"The size of multi_output_channel (%d) does not match "
|
|
"the size of multi_consume_channel (%d).",
|
|
multi_output_channel_.size(),
|
|
multi_consume_channel_.size()));
|
|
|
|
for (size_t i = 0; i < multi_output_channel_.size(); ++i) {
|
|
output_channels_data_size += multi_output_channel_[i]->Size();
|
|
consume_channels_data_size += multi_consume_channel_[i]->Size();
|
|
}
|
|
|
|
if (output_channels_data_size != 0) {
|
|
PADDLE_ENFORCE_EQ(consume_channels_data_size,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"When output_channels_data_size (%d) is not zero, "
|
|
"consume_channels_data_size (%d) should be zero.",
|
|
output_channels_data_size,
|
|
consume_channels_data_size));
|
|
cur_channel = 0;
|
|
} else {
|
|
PADDLE_ENFORCE_EQ(
|
|
output_channels_data_size,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"When output_channels_data_size is zero, it should be zero. "
|
|
"consume_channels_data_size: %d",
|
|
consume_channels_data_size));
|
|
cur_channel = 1;
|
|
}
|
|
|
|
if (cur_channel == 0) { // NOLINT
|
|
origin_channels = &multi_output_channel_;
|
|
other_channels = &multi_consume_channel_;
|
|
origin_pv_channels = &multi_pv_output_;
|
|
other_pv_channels = &multi_pv_consume_;
|
|
} else {
|
|
origin_channels = &multi_consume_channel_;
|
|
other_channels = &multi_output_channel_;
|
|
origin_pv_channels = &multi_pv_consume_;
|
|
other_pv_channels = &multi_pv_output_;
|
|
}
|
|
PADDLE_ENFORCE_NOT_NULL(origin_channels,
|
|
common::errors::InvalidArgument(
|
|
"origin_channels should not be nullptr, please "
|
|
"check if it is properly initialized."));
|
|
PADDLE_ENFORCE_NOT_NULL(other_channels,
|
|
common::errors::InvalidArgument(
|
|
"other_channels should not be nullptr, "
|
|
"ensure it is correctly set before usage."));
|
|
PADDLE_ENFORCE_NOT_NULL(
|
|
origin_pv_channels,
|
|
common::errors::InvalidArgument("origin_pv_channels must not be nullptr, "
|
|
"verify its initialization."));
|
|
PADDLE_ENFORCE_NOT_NULL(
|
|
other_pv_channels,
|
|
common::errors::InvalidArgument(
|
|
"other_pv_channels must not be nullptr, confirm its setup."));
|
|
|
|
paddle::framework::Channel<T> total_data_channel =
|
|
paddle::framework::MakeChannel<T>();
|
|
std::vector<paddle::framework::Channel<T>> new_channels;
|
|
std::vector<paddle::framework::Channel<T>> new_other_channels;
|
|
std::vector<paddle::framework::Channel<PvInstance>> new_pv_channels;
|
|
std::vector<paddle::framework::Channel<PvInstance>> new_other_pv_channels;
|
|
|
|
std::vector<T> local_vec;
|
|
for (size_t i = 0; i < origin_channels->size(); ++i) {
|
|
local_vec.clear();
|
|
(*origin_channels)[i]->Close();
|
|
(*origin_channels)[i]->ReadAll(local_vec);
|
|
total_data_channel->Write(std::move(local_vec));
|
|
}
|
|
total_data_channel->Close();
|
|
if (static_cast<int>(total_data_channel->Size()) >= channel_num) {
|
|
total_data_channel->SetBlockSize(total_data_channel->Size() / channel_num +
|
|
(discard_remaining_ins ? 0 : 1));
|
|
}
|
|
if (static_cast<int>(input_channel_->Size()) >= channel_num) {
|
|
input_channel_->SetBlockSize(input_channel_->Size() / channel_num +
|
|
(discard_remaining_ins ? 0 : 1));
|
|
}
|
|
if (static_cast<int>(input_pv_channel_->Size()) >= channel_num) {
|
|
input_pv_channel_->SetBlockSize(input_pv_channel_->Size() / channel_num +
|
|
(discard_remaining_ins ? 0 : 1));
|
|
VLOG(3) << "now input_pv_channel block size is "
|
|
<< input_pv_channel_->BlockSize();
|
|
}
|
|
|
|
for (int i = 0; i < channel_num; ++i) {
|
|
local_vec.clear();
|
|
total_data_channel->Read(local_vec);
|
|
new_other_channels.push_back(paddle::framework::MakeChannel<T>());
|
|
new_channels.push_back(paddle::framework::MakeChannel<T>());
|
|
new_channels[i]->Write(std::move(local_vec));
|
|
new_other_pv_channels.push_back(
|
|
paddle::framework::MakeChannel<PvInstance>());
|
|
new_pv_channels.push_back(paddle::framework::MakeChannel<PvInstance>());
|
|
}
|
|
|
|
total_data_channel->Clear();
|
|
origin_channels->clear();
|
|
other_channels->clear();
|
|
*origin_channels = new_channels;
|
|
*other_channels = new_other_channels;
|
|
|
|
origin_pv_channels->clear();
|
|
other_pv_channels->clear();
|
|
*origin_pv_channels = new_pv_channels;
|
|
*other_pv_channels = new_other_pv_channels;
|
|
|
|
new_channels.clear();
|
|
new_other_channels.clear();
|
|
std::vector<paddle::framework::Channel<T>>().swap(new_channels);
|
|
std::vector<paddle::framework::Channel<T>>().swap(new_other_channels);
|
|
|
|
new_pv_channels.clear();
|
|
new_other_pv_channels.clear();
|
|
std::vector<paddle::framework::Channel<PvInstance>>().swap(new_pv_channels);
|
|
std::vector<paddle::framework::Channel<PvInstance>>().swap(
|
|
new_other_pv_channels);
|
|
|
|
local_vec.clear();
|
|
std::vector<T>().swap(local_vec);
|
|
VLOG(3) << "adjust channel num done";
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::DynamicAdjustReadersNum(int thread_num) {
|
|
if (thread_num_ == thread_num) {
|
|
VLOG(3) << "DatasetImpl<T>::DynamicAdjustReadersNum thread_num_="
|
|
<< thread_num_ << ", thread_num_=thread_num, no need to adjust";
|
|
return;
|
|
}
|
|
VLOG(3) << "adjust readers num from " << thread_num_ << " to " << thread_num;
|
|
thread_num_ = thread_num;
|
|
std::vector<std::shared_ptr<paddle::framework::DataFeed>>().swap(readers_);
|
|
CreateReaders();
|
|
VLOG(3) << "adjust readers num done";
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetFleetSendSleepSeconds(int seconds) {
|
|
fleet_send_sleep_seconds_ = seconds;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::CreateReaders() {
|
|
VLOG(3) << "Calling CreateReaders()";
|
|
VLOG(3) << "thread num in Dataset: " << thread_num_;
|
|
VLOG(3) << "Filelist size in Dataset: " << filelist_.size();
|
|
VLOG(3) << "channel num in Dataset: " << channel_num_;
|
|
PADDLE_ENFORCE_GT(thread_num_,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The number of threads (thread_num) should "
|
|
"be greater than 0. Received: %d",
|
|
thread_num_));
|
|
PADDLE_ENFORCE_GT(
|
|
channel_num_,
|
|
0,
|
|
common::errors::InvalidArgument("The number of channels (channel_num) "
|
|
"should be greater than 0. Received: %d",
|
|
channel_num_));
|
|
PADDLE_ENFORCE_LE(channel_num_,
|
|
thread_num_,
|
|
common::errors::InvalidArgument(
|
|
"The number of channels (channel_num) should be less "
|
|
"than or equal to the number of threads (thread_num). "
|
|
"Received channel_num: %d, thread_num: %d",
|
|
channel_num_,
|
|
thread_num_));
|
|
|
|
VLOG(3) << "readers size: " << readers_.size();
|
|
if (!readers_.empty()) {
|
|
VLOG(3) << "readers_.size() = " << readers_.size()
|
|
<< ", will not create again";
|
|
return;
|
|
}
|
|
VLOG(3) << "data feed class name: " << data_feed_desc_.name();
|
|
int channel_idx = 0;
|
|
for (int i = 0; i < thread_num_; ++i) {
|
|
readers_.push_back(DataFeedFactory::CreateDataFeed(data_feed_desc_.name()));
|
|
readers_[i]->Init(data_feed_desc_);
|
|
readers_[i]->SetThreadId(i);
|
|
readers_[i]->SetThreadNum(thread_num_);
|
|
readers_[i]->SetFileListMutex(&mutex_for_pick_file_);
|
|
readers_[i]->SetFileListIndex(&file_idx_);
|
|
readers_[i]->SetFeaNumMutex(&mutex_for_fea_num_);
|
|
readers_[i]->SetFeaNum(&total_fea_num_);
|
|
readers_[i]->SetFileList(filelist_);
|
|
readers_[i]->SetParseInsId(parse_ins_id_);
|
|
readers_[i]->SetParseUid(parse_uid_);
|
|
readers_[i]->SetParseContent(parse_content_);
|
|
readers_[i]->SetParseLogKey(parse_logkey_);
|
|
readers_[i]->SetEnablePvMerge(enable_pv_merge_);
|
|
// Notice: it is only valid for untest of test_paddlebox_datafeed.
|
|
// In fact, it does not affect the train process when paddle is
|
|
// complied with Box_Ps.
|
|
readers_[i]->SetCurrentPhase(current_phase_);
|
|
if (input_channel_ != nullptr) {
|
|
readers_[i]->SetInputChannel(input_channel_.get());
|
|
}
|
|
if (input_pv_channel_ != nullptr) {
|
|
readers_[i]->SetInputPvChannel(input_pv_channel_.get());
|
|
}
|
|
if (cur_channel_ == 0 && static_cast<size_t>(channel_idx) <
|
|
multi_output_channel_.size()) { // NOLINT
|
|
readers_[i]->SetOutputChannel(multi_output_channel_[channel_idx].get());
|
|
readers_[i]->SetConsumeChannel(multi_consume_channel_[channel_idx].get());
|
|
readers_[i]->SetOutputPvChannel(multi_pv_output_[channel_idx].get());
|
|
readers_[i]->SetConsumePvChannel(multi_pv_consume_[channel_idx].get());
|
|
} else if (static_cast<size_t>(channel_idx) <
|
|
multi_output_channel_.size()) {
|
|
readers_[i]->SetOutputChannel(multi_consume_channel_[channel_idx].get());
|
|
readers_[i]->SetConsumeChannel(multi_output_channel_[channel_idx].get());
|
|
readers_[i]->SetOutputPvChannel(multi_pv_consume_[channel_idx].get());
|
|
readers_[i]->SetConsumePvChannel(multi_pv_output_[channel_idx].get());
|
|
}
|
|
++channel_idx;
|
|
if (channel_idx >= channel_num_) {
|
|
channel_idx = 0;
|
|
}
|
|
}
|
|
VLOG(3) << "readers size: " << readers_.size();
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::DestroyReaders() {
|
|
VLOG(3) << "Calling DestroyReaders()";
|
|
VLOG(3) << "readers size1: " << readers_.size();
|
|
std::vector<std::shared_ptr<paddle::framework::DataFeed>>().swap(readers_);
|
|
VLOG(3) << "readers size: " << readers_.size();
|
|
file_idx_ = 0;
|
|
cur_channel_ = 1 - cur_channel_;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::SetPreLoadThreadNum(int thread_num) {
|
|
preload_thread_num_ = thread_num;
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::CreatePreLoadReaders() {
|
|
VLOG(3) << "Begin CreatePreLoadReaders";
|
|
if (preload_thread_num_ == 0) {
|
|
preload_thread_num_ = thread_num_;
|
|
}
|
|
PADDLE_ENFORCE_GT(preload_thread_num_,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The number of preload threads (preload_thread_num) "
|
|
"should be greater than 0. Received: %d",
|
|
preload_thread_num_));
|
|
PADDLE_ENFORCE_NOT_NULL(input_channel_,
|
|
common::errors::InvalidArgument(
|
|
"The input_channel should not be nullptr. Please "
|
|
"ensure it is properly initialized."));
|
|
|
|
preload_readers_.clear();
|
|
for (int i = 0; i < preload_thread_num_; ++i) {
|
|
preload_readers_.push_back(
|
|
DataFeedFactory::CreateDataFeed(data_feed_desc_.name()));
|
|
preload_readers_[i]->Init(data_feed_desc_);
|
|
preload_readers_[i]->SetThreadId(i);
|
|
preload_readers_[i]->SetThreadNum(preload_thread_num_);
|
|
preload_readers_[i]->SetFileListMutex(&mutex_for_pick_file_);
|
|
preload_readers_[i]->SetFileListIndex(&file_idx_);
|
|
preload_readers_[i]->SetFileList(filelist_);
|
|
preload_readers_[i]->SetFeaNumMutex(&mutex_for_fea_num_);
|
|
preload_readers_[i]->SetFeaNum(&total_fea_num_);
|
|
preload_readers_[i]->SetParseInsId(parse_ins_id_);
|
|
preload_readers_[i]->SetParseUid(parse_uid_);
|
|
preload_readers_[i]->SetParseContent(parse_content_);
|
|
preload_readers_[i]->SetParseLogKey(parse_logkey_);
|
|
preload_readers_[i]->SetEnablePvMerge(enable_pv_merge_);
|
|
preload_readers_[i]->SetInputChannel(input_channel_.get());
|
|
preload_readers_[i]->SetOutputChannel(nullptr);
|
|
preload_readers_[i]->SetConsumeChannel(nullptr);
|
|
preload_readers_[i]->SetOutputPvChannel(nullptr);
|
|
preload_readers_[i]->SetConsumePvChannel(nullptr);
|
|
}
|
|
VLOG(3) << "End CreatePreLoadReaders";
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::DestroyPreLoadReaders() {
|
|
VLOG(3) << "Begin DestroyPreLoadReaders";
|
|
preload_readers_.clear();
|
|
std::vector<std::shared_ptr<paddle::framework::DataFeed>>().swap(
|
|
preload_readers_);
|
|
file_idx_ = 0;
|
|
VLOG(3) << "End DestroyPreLoadReaders";
|
|
}
|
|
|
|
template <typename T>
|
|
int64_t DatasetImpl<T>::GetMemoryDataSize() {
|
|
if (gpu_graph_mode_) {
|
|
bool is_multi_node = false, sage_mode = false, gpu_graph_training = true;
|
|
int64_t total_path_num = 0;
|
|
for (int i = 0; i < thread_num_; i++) {
|
|
is_multi_node = readers_[i]->GetMultiNodeMode();
|
|
sage_mode = readers_[i]->GetSageMode();
|
|
gpu_graph_training = readers_[i]->GetTrainState();
|
|
if (is_multi_node && sage_mode && gpu_graph_training) {
|
|
total_path_num += readers_[i]->GetTrainMemoryDataSize();
|
|
} else {
|
|
total_path_num += readers_[i]->GetGraphPathNum();
|
|
}
|
|
}
|
|
return total_path_num;
|
|
} else {
|
|
return input_channel_->Size();
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
bool DatasetImpl<T>::GetEpochFinish() {
|
|
#if defined(PADDLE_WITH_HETERPS)
|
|
bool is_epoch_finish = true;
|
|
if (gpu_graph_mode_) {
|
|
for (int i = 0; i < thread_num_; i++) {
|
|
is_epoch_finish = is_epoch_finish && readers_[i]->get_epoch_finish();
|
|
}
|
|
}
|
|
return is_epoch_finish;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
template <typename T>
|
|
void DatasetImpl<T>::ClearSampleState() {
|
|
#if defined(PADDLE_WITH_PSCORE) && defined(PADDLE_WITH_HETERPS)
|
|
for (size_t i = 0; i < readers_.size(); i++) {
|
|
readers_[i]->ClearSampleState();
|
|
readers_[i]->ResetPathNum();
|
|
readers_[i]->ResetEpochFinish();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
template <typename T>
|
|
int64_t DatasetImpl<T>::GetPvDataSize() {
|
|
if (enable_pv_merge_) {
|
|
return input_pv_channel_->Size();
|
|
} else {
|
|
VLOG(0) << "It does not merge pv..";
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
template <typename T>
|
|
int64_t DatasetImpl<T>::GetShuffleDataSize() {
|
|
int64_t sum = 0;
|
|
for (size_t i = 0; i < multi_output_channel_.size(); ++i) {
|
|
sum += multi_output_channel_[i]->Size() + multi_consume_channel_[i]->Size();
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
int MultiSlotDataset::ReceiveFromClient(int msg_type,
|
|
int client_id,
|
|
const std::string& msg) {
|
|
#ifdef _LINUX
|
|
VLOG(3) << "ReceiveFromClient msg_type=" << msg_type
|
|
<< ", client_id=" << client_id << ", msg length=" << msg.length();
|
|
if (msg.length() == 0) {
|
|
return 0;
|
|
}
|
|
paddle::framework::BinaryArchive ar;
|
|
ar.SetReadBuffer(const_cast<char*>(msg.c_str()), msg.length(), nullptr);
|
|
if (ar.Cursor() == ar.Finish()) {
|
|
return 0;
|
|
}
|
|
std::vector<Record> data;
|
|
while (ar.Cursor() < ar.Finish()) {
|
|
data.push_back(ar.Get<Record>());
|
|
}
|
|
PADDLE_ENFORCE_EQ(ar.Cursor(),
|
|
ar.Finish(),
|
|
common::errors::InvalidArgument(
|
|
"Cursor position does not match finish position. The "
|
|
"cursor should be at the finish position. Received "
|
|
"cursor position: %d, expected finish position: %d.",
|
|
ar.Cursor(),
|
|
ar.Finish()));
|
|
|
|
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
|
// not use random because it doesn't perform well here.
|
|
// to make sure each channel get data equally, we just put data to
|
|
// channel one by one.
|
|
// int64_t index = fleet_ptr->LocalRandomEngine()() % channel_num_;
|
|
int64_t index = 0;
|
|
{
|
|
std::unique_lock<std::mutex> lk(global_index_mutex_);
|
|
index = global_index_++;
|
|
}
|
|
index = index % channel_num_;
|
|
VLOG(3) << "random index=" << index;
|
|
multi_output_channel_[index]->Write(std::move(data));
|
|
|
|
data.clear();
|
|
data.shrink_to_fit();
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
// explicit instantiation
|
|
template class DatasetImpl<Record>;
|
|
|
|
void MultiSlotDataset::DynamicAdjustReadersNum(int thread_num) {
|
|
if (thread_num_ == thread_num) {
|
|
VLOG(3) << "DatasetImpl<T>::DynamicAdjustReadersNum thread_num_="
|
|
<< thread_num_ << ", thread_num_=thread_num, no need to adjust";
|
|
return;
|
|
}
|
|
VLOG(3) << "adjust readers num from " << thread_num_ << " to " << thread_num;
|
|
thread_num_ = thread_num;
|
|
std::vector<std::shared_ptr<paddle::framework::DataFeed>>().swap(readers_);
|
|
CreateReaders();
|
|
VLOG(3) << "adjust readers num done";
|
|
PrepareTrain();
|
|
}
|
|
|
|
void MultiSlotDataset::PostprocessInstance() {
|
|
// divide pv instance, and merge to input_channel_
|
|
if (enable_pv_merge_) {
|
|
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
|
std::shuffle(input_records_.begin(),
|
|
input_records_.end(),
|
|
fleet_ptr->LocalRandomEngine());
|
|
input_channel_->Open();
|
|
input_channel_->Write(std::move(input_records_));
|
|
for (auto& pv_consume : multi_pv_consume_) {
|
|
pv_consume->Clear();
|
|
}
|
|
input_channel_->Close();
|
|
input_records_.clear();
|
|
input_records_.shrink_to_fit();
|
|
} else {
|
|
input_channel_->Open();
|
|
for (auto& consume_channel : multi_consume_channel_) {
|
|
std::vector<Record> ins_data;
|
|
consume_channel->Close();
|
|
consume_channel->ReadAll(ins_data);
|
|
input_channel_->Write(std::move(ins_data));
|
|
ins_data.clear();
|
|
ins_data.shrink_to_fit();
|
|
consume_channel->Clear();
|
|
}
|
|
input_channel_->Close();
|
|
this->LocalShuffle();
|
|
}
|
|
}
|
|
|
|
void MultiSlotDataset::SetCurrentPhase(int current_phase) {
|
|
current_phase_ = current_phase;
|
|
}
|
|
|
|
void MultiSlotDataset::PreprocessInstance() {
|
|
if (!input_channel_ || input_channel_->Size() == 0) {
|
|
return;
|
|
}
|
|
if (!enable_pv_merge_) { // means to use Record
|
|
this->LocalShuffle();
|
|
} else { // means to use Pv
|
|
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
|
input_channel_->Close();
|
|
std::vector<PvInstance> pv_data;
|
|
input_channel_->ReadAll(input_records_);
|
|
int all_records_num = static_cast<int>(input_records_.size());
|
|
std::vector<Record*> all_records;
|
|
all_records.reserve(all_records_num);
|
|
for (int index = 0; index < all_records_num; ++index) {
|
|
all_records.push_back(&input_records_[index]);
|
|
}
|
|
|
|
std::sort(all_records.data(),
|
|
all_records.data() + all_records_num,
|
|
[](const Record* lhs, const Record* rhs) {
|
|
return lhs->search_id < rhs->search_id;
|
|
});
|
|
if (merge_by_sid_) {
|
|
uint64_t last_search_id = 0;
|
|
for (int i = 0; i < all_records_num; ++i) {
|
|
Record* ins = all_records[i];
|
|
if (i == 0 || last_search_id != ins->search_id) {
|
|
PvInstance pv_instance = make_pv_instance();
|
|
pv_instance->merge_instance(ins);
|
|
pv_data.push_back(pv_instance);
|
|
last_search_id = ins->search_id;
|
|
continue;
|
|
}
|
|
pv_data.back()->merge_instance(ins);
|
|
}
|
|
} else {
|
|
for (int i = 0; i < all_records_num; ++i) {
|
|
Record* ins = all_records[i];
|
|
PvInstance pv_instance = make_pv_instance();
|
|
pv_instance->merge_instance(ins);
|
|
pv_data.push_back(pv_instance);
|
|
}
|
|
}
|
|
|
|
std::shuffle(
|
|
pv_data.begin(), pv_data.end(), fleet_ptr->LocalRandomEngine());
|
|
input_pv_channel_->Open();
|
|
input_pv_channel_->Write(std::move(pv_data));
|
|
|
|
pv_data.clear();
|
|
pv_data.shrink_to_fit();
|
|
input_pv_channel_->Close();
|
|
}
|
|
}
|
|
|
|
void MultiSlotDataset::GenerateLocalTablesUnlock(int table_id,
|
|
int feadim,
|
|
int read_thread_num,
|
|
int consume_thread_num,
|
|
int shard_num) {
|
|
VLOG(3) << "MultiSlotDataset::GenerateUniqueFeasign begin";
|
|
if (!gen_uni_feasigns_) {
|
|
VLOG(3) << "generate_unique_feasign_=false, will not GenerateUniqueFeasign";
|
|
return;
|
|
}
|
|
|
|
PADDLE_ENFORCE_NE(
|
|
multi_output_channel_.size(),
|
|
0,
|
|
common::errors::InvalidArgument("The size of multi_output_channel should "
|
|
"not be zero. Received size: %zu.",
|
|
multi_output_channel_.size()));
|
|
// NOLINT
|
|
auto fleet_ptr_ = framework::FleetWrapper::GetInstance();
|
|
std::vector<std::unordered_map<uint64_t, std::vector<float>>>&
|
|
local_map_tables = fleet_ptr_->GetLocalTable();
|
|
local_map_tables.resize(shard_num);
|
|
// read thread
|
|
int channel_num = static_cast<int>(multi_output_channel_.size());
|
|
if (read_thread_num < channel_num) {
|
|
read_thread_num = channel_num;
|
|
}
|
|
std::vector<std::thread> threads(read_thread_num);
|
|
consume_task_pool_.resize(consume_thread_num);
|
|
for (auto& consume_task : consume_task_pool_) {
|
|
consume_task.reset(new ::ThreadPool(1));
|
|
}
|
|
auto consume_func = [&local_map_tables](int shard_id,
|
|
int feadim,
|
|
std::vector<uint64_t>& keys) {
|
|
for (auto k : keys) {
|
|
if (local_map_tables[shard_id].find(k) ==
|
|
local_map_tables[shard_id].end()) {
|
|
local_map_tables[shard_id][k] = std::vector<float>(feadim, 0);
|
|
}
|
|
}
|
|
};
|
|
auto gen_func = [this, &shard_num, &feadim, &consume_func](int i) {
|
|
std::vector<Record> vec_data;
|
|
std::vector<std::vector<uint64_t>> task_keys(shard_num);
|
|
std::vector<std::future<void>> task_futures;
|
|
this->multi_output_channel_[i]->Close();
|
|
this->multi_output_channel_[i]->ReadAll(vec_data);
|
|
for (auto& item : vec_data) {
|
|
for (auto& feature : item.uint64_feasigns_) {
|
|
int shard =
|
|
static_cast<int>(feature.sign().uint64_feasign_ % shard_num);
|
|
task_keys[shard].push_back(feature.sign().uint64_feasign_);
|
|
}
|
|
}
|
|
|
|
for (int shard_id = 0; shard_id < shard_num; shard_id++) {
|
|
task_futures.emplace_back(consume_task_pool_[shard_id]->enqueue(
|
|
consume_func, shard_id, feadim, task_keys[shard_id]));
|
|
}
|
|
|
|
multi_output_channel_[i]->Open();
|
|
multi_output_channel_[i]->Write(std::move(vec_data));
|
|
vec_data.clear();
|
|
vec_data.shrink_to_fit();
|
|
for (auto& tk : task_keys) {
|
|
tk.clear();
|
|
std::vector<uint64_t>().swap(tk);
|
|
}
|
|
task_keys.clear();
|
|
std::vector<std::vector<uint64_t>>().swap(task_keys);
|
|
for (auto& tf : task_futures) {
|
|
tf.wait();
|
|
}
|
|
};
|
|
for (size_t i = 0; i < threads.size(); i++) {
|
|
threads[i] = std::thread(gen_func, i);
|
|
}
|
|
for (std::thread& t : threads) {
|
|
t.join();
|
|
}
|
|
for (auto& consume_task : consume_task_pool_) {
|
|
consume_task.reset();
|
|
}
|
|
consume_task_pool_.clear();
|
|
fleet_ptr_->PullSparseToLocal(table_id, feadim);
|
|
}
|
|
|
|
void MultiSlotDataset::MergeByInsId() {
|
|
VLOG(3) << "MultiSlotDataset::MergeByInsId begin";
|
|
if (!merge_by_ins_id_) {
|
|
VLOG(3) << "merge_by_ins_id=false, will not MergeByInsId";
|
|
return;
|
|
}
|
|
auto multi_slot_desc = data_feed_desc_.multi_slot_desc();
|
|
std::vector<std::string> use_slots;
|
|
std::vector<bool> use_slots_is_dense;
|
|
for (int i = 0; i < multi_slot_desc.slots_size(); ++i) {
|
|
const auto& slot = multi_slot_desc.slots(i);
|
|
if (slot.is_used()) {
|
|
use_slots.push_back(slot.name());
|
|
use_slots_is_dense.push_back(slot.is_dense());
|
|
}
|
|
}
|
|
PADDLE_ENFORCE_NE(
|
|
multi_output_channel_.size(),
|
|
0,
|
|
common::errors::InvalidArgument("The size of multi_output_channel should "
|
|
"not be zero. Received size: %zu.",
|
|
multi_output_channel_.size()));
|
|
// NOLINT
|
|
auto channel_data = paddle::framework::MakeChannel<Record>();
|
|
VLOG(3) << "multi_output_channel_.size() " << multi_output_channel_.size();
|
|
for (auto& item : multi_output_channel_) {
|
|
std::vector<Record> vec_data;
|
|
item->Close();
|
|
item->ReadAll(vec_data);
|
|
channel_data->Write(std::move(vec_data));
|
|
vec_data.clear();
|
|
vec_data.shrink_to_fit();
|
|
item->Clear();
|
|
}
|
|
channel_data->Close();
|
|
std::vector<Record> recs;
|
|
recs.reserve(channel_data->Size());
|
|
channel_data->ReadAll(recs);
|
|
channel_data->Clear();
|
|
std::sort(recs.begin(), recs.end(), [](const Record& a, const Record& b) {
|
|
return a.ins_id_ < b.ins_id_;
|
|
});
|
|
|
|
std::vector<Record> results;
|
|
uint64_t drop_ins_num = 0;
|
|
std::unordered_set<uint16_t> all_int64;
|
|
std::unordered_set<uint16_t> all_float;
|
|
std::unordered_set<uint16_t> local_uint64;
|
|
std::unordered_set<uint16_t> local_float;
|
|
std::unordered_map<uint16_t, std::vector<FeatureItem>> all_dense_uint64;
|
|
std::unordered_map<uint16_t, std::vector<FeatureItem>> all_dense_float;
|
|
std::unordered_map<uint16_t, std::vector<FeatureItem>> local_dense_uint64;
|
|
std::unordered_map<uint16_t, std::vector<FeatureItem>> local_dense_float;
|
|
std::unordered_map<uint16_t, bool> dense_empty;
|
|
|
|
VLOG(3) << "recs.size() " << recs.size();
|
|
for (size_t i = 0; i < recs.size();) {
|
|
size_t j = i + 1;
|
|
while (j < recs.size() && recs[j].ins_id_ == recs[i].ins_id_) {
|
|
j++;
|
|
}
|
|
if (merge_size_ > 0 && j - i != merge_size_) {
|
|
drop_ins_num += j - i;
|
|
LOG(WARNING) << "drop ins " << recs[i].ins_id_ << " size=" << j - i
|
|
<< ", because merge_size=" << merge_size_;
|
|
i = j;
|
|
continue;
|
|
}
|
|
|
|
all_int64.clear();
|
|
all_float.clear();
|
|
all_dense_uint64.clear();
|
|
all_dense_float.clear();
|
|
bool has_conflict_slot = false;
|
|
uint16_t conflict_slot = 0;
|
|
|
|
Record rec;
|
|
rec.ins_id_ = recs[i].ins_id_;
|
|
rec.content_ = recs[i].content_;
|
|
|
|
for (size_t k = i; k < j; k++) {
|
|
dense_empty.clear();
|
|
local_dense_uint64.clear();
|
|
local_dense_float.clear();
|
|
for (auto& feature : recs[k].uint64_feasigns_) {
|
|
uint16_t slot = feature.slot();
|
|
if (!use_slots_is_dense[slot]) {
|
|
continue;
|
|
}
|
|
local_dense_uint64[slot].push_back(feature);
|
|
if (feature.sign().uint64_feasign_ != 0) {
|
|
dense_empty[slot] = false;
|
|
} else if (dense_empty.find(slot) == dense_empty.end() &&
|
|
all_dense_uint64.find(slot) == all_dense_uint64.end()) {
|
|
dense_empty[slot] = true;
|
|
}
|
|
}
|
|
for (auto& feature : recs[k].float_feasigns_) {
|
|
uint16_t slot = feature.slot();
|
|
if (!use_slots_is_dense[slot]) {
|
|
continue;
|
|
}
|
|
local_dense_float[slot].push_back(feature);
|
|
if (fabs(feature.sign().float_feasign_) >= 1e-6) {
|
|
dense_empty[slot] = false;
|
|
} else if (dense_empty.find(slot) == dense_empty.end() &&
|
|
all_dense_float.find(slot) == all_dense_float.end()) {
|
|
dense_empty[slot] = true;
|
|
}
|
|
}
|
|
for (auto& p : dense_empty) {
|
|
if (local_dense_uint64.find(p.first) != local_dense_uint64.end()) {
|
|
all_dense_uint64[p.first] = std::move(local_dense_uint64[p.first]);
|
|
} else if (local_dense_float.find(p.first) != local_dense_float.end()) {
|
|
all_dense_float[p.first] = std::move(local_dense_float[p.first]);
|
|
}
|
|
}
|
|
}
|
|
for (auto& f : all_dense_uint64) {
|
|
rec.uint64_feasigns_.insert(
|
|
rec.uint64_feasigns_.end(), f.second.begin(), f.second.end());
|
|
}
|
|
for (auto& f : all_dense_float) {
|
|
rec.float_feasigns_.insert(
|
|
rec.float_feasigns_.end(), f.second.begin(), f.second.end());
|
|
}
|
|
|
|
for (size_t k = i; k < j; k++) {
|
|
local_uint64.clear();
|
|
local_float.clear();
|
|
for (auto& feature : recs[k].uint64_feasigns_) {
|
|
uint16_t slot = feature.slot();
|
|
if (use_slots_is_dense[slot]) {
|
|
continue;
|
|
} else if (all_int64.find(slot) != all_int64.end()) {
|
|
has_conflict_slot = true;
|
|
conflict_slot = slot;
|
|
break;
|
|
}
|
|
local_uint64.insert(slot);
|
|
rec.uint64_feasigns_.push_back(feature);
|
|
}
|
|
if (has_conflict_slot) {
|
|
break;
|
|
}
|
|
all_int64.insert(local_uint64.begin(), local_uint64.end());
|
|
|
|
for (auto& feature : recs[k].float_feasigns_) {
|
|
uint16_t slot = feature.slot();
|
|
if (use_slots_is_dense[slot]) {
|
|
continue;
|
|
} else if (all_float.find(slot) != all_float.end()) {
|
|
has_conflict_slot = true;
|
|
conflict_slot = slot;
|
|
break;
|
|
}
|
|
local_float.insert(slot);
|
|
rec.float_feasigns_.push_back(feature);
|
|
}
|
|
if (has_conflict_slot) {
|
|
break;
|
|
}
|
|
all_float.insert(local_float.begin(), local_float.end());
|
|
}
|
|
|
|
if (has_conflict_slot) {
|
|
LOG(WARNING) << "drop ins " << recs[i].ins_id_ << " size=" << j - i
|
|
<< ", because conflict_slot=" << use_slots[conflict_slot];
|
|
drop_ins_num += j - i;
|
|
} else {
|
|
results.push_back(std::move(rec));
|
|
}
|
|
i = j;
|
|
}
|
|
std::vector<Record>().swap(recs);
|
|
VLOG(3) << "results size " << results.size();
|
|
LOG(WARNING) << "total drop ins num: " << drop_ins_num;
|
|
results.shrink_to_fit();
|
|
|
|
auto fleet_ptr = framework::FleetWrapper::GetInstance();
|
|
std::shuffle(results.begin(), results.end(), fleet_ptr->LocalRandomEngine());
|
|
channel_data->Open();
|
|
channel_data->Write(std::move(results));
|
|
channel_data->Close();
|
|
results.clear();
|
|
results.shrink_to_fit();
|
|
VLOG(3) << "channel data size " << channel_data->Size();
|
|
channel_data->SetBlockSize(channel_data->Size() / channel_num_ + 1);
|
|
VLOG(3) << "channel data block size " << channel_data->BlockSize();
|
|
for (auto& item : multi_output_channel_) {
|
|
std::vector<Record> vec_data;
|
|
channel_data->Read(vec_data);
|
|
item->Open();
|
|
item->Write(std::move(vec_data));
|
|
vec_data.clear();
|
|
vec_data.shrink_to_fit();
|
|
}
|
|
PADDLE_ENFORCE_EQ(
|
|
channel_data->Size(),
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The size of channel_data should be zero. Received size: %zu.",
|
|
channel_data->Size()));
|
|
// NOLINT
|
|
channel_data->Clear();
|
|
VLOG(3) << "MultiSlotDataset::MergeByInsId end";
|
|
}
|
|
|
|
void MultiSlotDataset::GetRandomData(
|
|
const std::unordered_set<uint16_t>& slots_to_replace,
|
|
std::vector<Record>* result) {
|
|
int debug_erase_cnt = 0;
|
|
int debug_push_cnt = 0;
|
|
auto multi_slot_desc = data_feed_desc_.multi_slot_desc();
|
|
slots_shuffle_rclist_.ReInit();
|
|
const auto& slots_shuffle_original_data = GetSlotsOriginalData();
|
|
for (const auto& rec : slots_shuffle_original_data) {
|
|
RecordCandidate rand_rec;
|
|
Record new_rec = rec;
|
|
slots_shuffle_rclist_.AddAndGet(rec, &rand_rec);
|
|
for (auto it = new_rec.uint64_feasigns_.begin();
|
|
it != new_rec.uint64_feasigns_.end();) {
|
|
if (slots_to_replace.find(it->slot()) != slots_to_replace.end()) {
|
|
it = new_rec.uint64_feasigns_.erase(it);
|
|
debug_erase_cnt += 1;
|
|
} else {
|
|
++it;
|
|
}
|
|
}
|
|
for (auto slot : slots_to_replace) {
|
|
auto range = rand_rec.feas_.equal_range(slot);
|
|
for (auto it = range.first; it != range.second; ++it) {
|
|
new_rec.uint64_feasigns_.emplace_back(it->second, it->first);
|
|
debug_push_cnt += 1;
|
|
}
|
|
}
|
|
result->push_back(std::move(new_rec));
|
|
}
|
|
VLOG(2) << "erase feasign num: " << debug_erase_cnt
|
|
<< " repush feasign num: " << debug_push_cnt;
|
|
}
|
|
|
|
void MultiSlotDataset::PreprocessChannel(
|
|
const std::set<std::string>& slots_to_replace,
|
|
std::unordered_set<uint16_t>& index_slots) { // NOLINT
|
|
int out_channel_size = 0;
|
|
if (cur_channel_ == 0) { // NOLINT
|
|
for (auto& item : multi_output_channel_) {
|
|
out_channel_size += static_cast<int>(item->Size());
|
|
}
|
|
} else {
|
|
for (auto& item : multi_consume_channel_) {
|
|
out_channel_size += static_cast<int>(item->Size());
|
|
}
|
|
}
|
|
VLOG(2) << "DatasetImpl<T>::SlotsShuffle() begin with input channel size: "
|
|
<< input_channel_->Size()
|
|
<< " output channel size: " << out_channel_size;
|
|
|
|
if ((!input_channel_ || input_channel_->Size() == 0) &&
|
|
slots_shuffle_original_data_.empty() && out_channel_size == 0) {
|
|
VLOG(3) << "DatasetImpl<T>::SlotsShuffle() end, no data to slots shuffle";
|
|
return;
|
|
}
|
|
|
|
auto multi_slot_desc = data_feed_desc_.multi_slot_desc();
|
|
for (int i = 0; i < multi_slot_desc.slots_size(); ++i) {
|
|
std::string cur_slot = multi_slot_desc.slots(i).name();
|
|
if (slots_to_replace.find(cur_slot) != slots_to_replace.end()) {
|
|
index_slots.insert(i);
|
|
}
|
|
}
|
|
if (slots_shuffle_original_data_.empty()) {
|
|
// before first slots shuffle, instances could be in
|
|
// input_channel, output_channel or consume_channel
|
|
if (input_channel_ && input_channel_->Size() != 0) {
|
|
slots_shuffle_original_data_.reserve(input_channel_->Size());
|
|
input_channel_->Close();
|
|
input_channel_->ReadAll(slots_shuffle_original_data_);
|
|
} else {
|
|
PADDLE_ENFORCE_GT(out_channel_size,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The out_channel_size should be greater "
|
|
"than 0. Received size: %d.",
|
|
out_channel_size));
|
|
// NOLINT
|
|
if (cur_channel_ == 0) { // NOLINT
|
|
for (auto& item : multi_output_channel_) {
|
|
std::vector<Record> vec_data;
|
|
item->Close();
|
|
item->ReadAll(vec_data);
|
|
slots_shuffle_original_data_.reserve(
|
|
slots_shuffle_original_data_.size() + vec_data.size());
|
|
slots_shuffle_original_data_.insert(
|
|
slots_shuffle_original_data_.end(),
|
|
std::make_move_iterator(vec_data.begin()),
|
|
std::make_move_iterator(vec_data.end()));
|
|
vec_data.clear();
|
|
vec_data.shrink_to_fit();
|
|
item->Clear();
|
|
}
|
|
} else {
|
|
for (auto& item : multi_consume_channel_) {
|
|
std::vector<Record> vec_data;
|
|
item->Close();
|
|
item->ReadAll(vec_data);
|
|
slots_shuffle_original_data_.reserve(
|
|
slots_shuffle_original_data_.size() + vec_data.size());
|
|
slots_shuffle_original_data_.insert(
|
|
slots_shuffle_original_data_.end(),
|
|
std::make_move_iterator(vec_data.begin()),
|
|
std::make_move_iterator(vec_data.end()));
|
|
vec_data.clear();
|
|
vec_data.shrink_to_fit();
|
|
item->Clear();
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// if already have original data for slots shuffle, clear channel
|
|
input_channel_->Clear();
|
|
if (cur_channel_ == 0) { // NOLINT
|
|
for (auto& item : multi_output_channel_) {
|
|
if (!item) {
|
|
continue;
|
|
}
|
|
item->Clear();
|
|
}
|
|
} else {
|
|
for (auto& item : multi_consume_channel_) {
|
|
if (!item) {
|
|
continue;
|
|
}
|
|
item->Clear();
|
|
}
|
|
}
|
|
}
|
|
// int end_size = 0;
|
|
// if (cur_channel_ == 0) { // NOLINT
|
|
// for (auto& item : multi_output_channel_) {
|
|
// if (!item) {
|
|
// continue;
|
|
// }
|
|
// end_size += static_cast<int>(item->Size());
|
|
// }
|
|
// } else {
|
|
// for (auto& item : multi_consume_channel_) {
|
|
// if (!item) {
|
|
// continue;
|
|
// }
|
|
// end_size += static_cast<int>(item->Size());
|
|
// }
|
|
// }
|
|
PADDLE_ENFORCE_EQ(input_channel_->Size(),
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The input channel should be empty before "
|
|
"slots shuffle. Received size: %zu.",
|
|
input_channel_->Size()));
|
|
}
|
|
|
|
// slots shuffle to input_channel_ with needed-shuffle slots
|
|
void MultiSlotDataset::SlotsShuffle(
|
|
const std::set<std::string>& slots_to_replace) {
|
|
PADDLE_ENFORCE_EQ(slots_shuffle_fea_eval_,
|
|
true,
|
|
common::errors::PreconditionNotMet(
|
|
"fea eval mode off, need to set on for slots shuffle"));
|
|
platform::Timer timeline;
|
|
timeline.Start();
|
|
std::unordered_set<uint16_t> index_slots;
|
|
PreprocessChannel(slots_to_replace, index_slots);
|
|
|
|
std::vector<Record> random_data;
|
|
random_data.clear();
|
|
// get slots shuffled random_data
|
|
GetRandomData(index_slots, &random_data);
|
|
input_channel_->Open();
|
|
input_channel_->Write(std::move(random_data));
|
|
random_data.clear();
|
|
random_data.shrink_to_fit();
|
|
input_channel_->Close();
|
|
cur_channel_ = 0;
|
|
|
|
timeline.Pause();
|
|
VLOG(2) << "DatasetImpl<T>::SlotsShuffle() end"
|
|
<< ", memory data size for slots shuffle=" << input_channel_->Size()
|
|
<< ", cost time=" << timeline.ElapsedSec() << " seconds";
|
|
}
|
|
|
|
template class DatasetImpl<SlotRecord>;
|
|
void SlotRecordDataset::CreateChannel() {
|
|
if (input_channel_ == nullptr) {
|
|
input_channel_ = paddle::framework::MakeChannel<SlotRecord>();
|
|
}
|
|
}
|
|
void SlotRecordDataset::CreateReaders() {
|
|
VLOG(3) << "Calling CreateReaders()";
|
|
VLOG(3) << "thread num in Dataset: " << thread_num_;
|
|
VLOG(3) << "Filelist size in Dataset: " << filelist_.size();
|
|
VLOG(3) << "channel num in Dataset: " << channel_num_;
|
|
PADDLE_ENFORCE_GT(
|
|
thread_num_,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The thread number should be greater than 0. Received: %d.",
|
|
thread_num_));
|
|
PADDLE_ENFORCE_GT(
|
|
channel_num_,
|
|
0,
|
|
common::errors::InvalidArgument(
|
|
"The channel number should be greater than 0. Received: %d.",
|
|
channel_num_));
|
|
PADDLE_ENFORCE_LE(
|
|
channel_num_,
|
|
thread_num_,
|
|
common::errors::InvalidArgument(
|
|
"The channel number should be less than or equal to the thread "
|
|
"number. Received channel number: %d, thread number: %d.",
|
|
channel_num_,
|
|
thread_num_));
|
|
|
|
VLOG(3) << "readers size: " << readers_.size();
|
|
if (!readers_.empty()) {
|
|
VLOG(3) << "readers_.size() = " << readers_.size()
|
|
<< ", will not create again";
|
|
return;
|
|
}
|
|
VLOG(3) << "data feed class name: " << data_feed_desc_.name()
|
|
<< "; gpu_graph_mode_:" << gpu_graph_mode_;
|
|
for (int i = 0; i < thread_num_; ++i) {
|
|
readers_.push_back(DataFeedFactory::CreateDataFeed(data_feed_desc_.name()));
|
|
readers_[i]->SetGpuGraphMode(gpu_graph_mode_);
|
|
readers_[i]->Init(data_feed_desc_);
|
|
readers_[i]->SetThreadId(i);
|
|
readers_[i]->SetThreadNum(thread_num_);
|
|
readers_[i]->SetFileListMutex(&mutex_for_pick_file_);
|
|
readers_[i]->SetFileListIndex(&file_idx_);
|
|
readers_[i]->SetFeaNumMutex(&mutex_for_fea_num_);
|
|
readers_[i]->SetFeaNum(&total_fea_num_);
|
|
readers_[i]->SetFileList(filelist_);
|
|
readers_[i]->SetParseInsId(parse_ins_id_);
|
|
readers_[i]->SetParseContent(parse_content_);
|
|
readers_[i]->SetParseLogKey(parse_logkey_);
|
|
readers_[i]->SetEnablePvMerge(enable_pv_merge_);
|
|
readers_[i]->SetCurrentPhase(current_phase_);
|
|
#if defined(PADDLE_WITH_PSCORE) && defined(PADDLE_WITH_HETERPS)
|
|
if (gpu_graph_mode_) {
|
|
readers_[i]->InitGraphResource();
|
|
}
|
|
#endif
|
|
if (input_channel_ != nullptr) {
|
|
readers_[i]->SetInputChannel(input_channel_.get());
|
|
}
|
|
}
|
|
VLOG(3) << "readers size: " << readers_.size();
|
|
}
|
|
|
|
void SlotRecordDataset::ReleaseMemory() {
|
|
VLOG(3) << "SlotRecordDataset::ReleaseMemory() begin";
|
|
platform::Timer timeline;
|
|
timeline.Start();
|
|
|
|
if (input_channel_) {
|
|
input_channel_->Clear();
|
|
input_channel_ = nullptr;
|
|
}
|
|
if (enable_heterps_) {
|
|
VLOG(3) << "put pool records size: " << input_records_.size();
|
|
SlotRecordPool().put(&input_records_);
|
|
input_records_.clear();
|
|
input_records_.shrink_to_fit();
|
|
VLOG(3) << "release heterps input records records size: "
|
|
<< input_records_.size();
|
|
}
|
|
|
|
readers_.clear();
|
|
readers_.shrink_to_fit();
|
|
|
|
std::vector<std::shared_ptr<paddle::framework::DataFeed>>().swap(readers_);
|
|
|
|
VLOG(3) << "SlotRecordDataset::ReleaseMemory() end";
|
|
VLOG(3) << "total_feasign_num_(" << STAT_GET(STAT_total_feasign_num_in_mem)
|
|
<< ") - current_fea_num_(" << total_fea_num_ << ") = ("
|
|
<< STAT_GET(STAT_total_feasign_num_in_mem) - total_fea_num_ << ")"
|
|
<< " object pool size=" << SlotRecordPool().capacity(); // For Debug
|
|
STAT_SUB(STAT_total_feasign_num_in_mem, total_fea_num_);
|
|
}
|
|
void SlotRecordDataset::GlobalShuffle(int thread_num) {
|
|
// TODO(yaoxuefeng)
|
|
return;
|
|
}
|
|
|
|
void SlotRecordDataset::DynamicAdjustChannelNum(int channel_num,
|
|
bool discard_remaining_ins) {
|
|
if (channel_num_ == channel_num) {
|
|
VLOG(3) << "DatasetImpl<T>::DynamicAdjustChannelNum channel_num_="
|
|
<< channel_num_ << ", channel_num_=channel_num, no need to adjust";
|
|
return;
|
|
}
|
|
VLOG(3) << "adjust channel num from " << channel_num_ << " to "
|
|
<< channel_num;
|
|
channel_num_ = channel_num;
|
|
|
|
if (static_cast<int>(input_channel_->Size()) >= channel_num) {
|
|
input_channel_->SetBlockSize(input_channel_->Size() / channel_num +
|
|
(discard_remaining_ins ? 0 : 1));
|
|
}
|
|
|
|
VLOG(3) << "adjust channel num done";
|
|
}
|
|
|
|
void SlotRecordDataset::PrepareTrain() {
|
|
#ifdef PADDLE_WITH_GLOO
|
|
if (enable_heterps_) {
|
|
if (input_records_.empty() && input_channel_ != nullptr &&
|
|
input_channel_->Size() != 0) {
|
|
input_channel_->ReadAll(input_records_);
|
|
VLOG(3) << "read from channel to records with records size: "
|
|
<< input_records_.size();
|
|
}
|
|
VLOG(3) << "input records size: " << input_records_.size();
|
|
int64_t total_ins_num = input_records_.size();
|
|
std::vector<std::pair<int, int>> offset;
|
|
int default_batch_size =
|
|
reinterpret_cast<SlotRecordInMemoryDataFeed*>(readers_[0].get())
|
|
->GetDefaultBatchSize();
|
|
VLOG(3) << "thread_num: " << thread_num_
|
|
<< " memory size: " << total_ins_num
|
|
<< " default batch_size: " << default_batch_size;
|
|
compute_thread_batch_nccl(
|
|
thread_num_, total_ins_num, default_batch_size, &offset);
|
|
VLOG(3) << "offset size: " << offset.size();
|
|
for (int i = 0; i < thread_num_; i++) {
|
|
reinterpret_cast<SlotRecordInMemoryDataFeed*>(readers_[i].get())
|
|
->SetRecord(&input_records_[0]);
|
|
}
|
|
for (size_t i = 0; i < offset.size(); i++) {
|
|
reinterpret_cast<SlotRecordInMemoryDataFeed*>(
|
|
readers_[i % thread_num_].get())
|
|
->AddBatchOffset(offset[i]);
|
|
}
|
|
}
|
|
#else
|
|
PADDLE_THROW(common::errors::Unavailable(
|
|
"dataset set heterps need compile with GLOO"));
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
void SlotRecordDataset::DynamicAdjustBatchNum() {
|
|
VLOG(3) << "dynamic adjust batch num of graph in multi node";
|
|
#if defined(PADDLE_WITH_PSCORE) && defined(PADDLE_WITH_HETERPS)
|
|
if (gpu_graph_mode_) {
|
|
bool sage_mode = 0;
|
|
int thread_max_batch_num = 0;
|
|
for (size_t i = 0; i < readers_.size(); i++) {
|
|
sage_mode = readers_[i]->GetSageMode();
|
|
int batch_size = readers_[i]->GetCurBatchSize();
|
|
int64_t ins_num = readers_[i]->GetGraphPathNum();
|
|
int batch_num = (ins_num + batch_size - 1) / batch_size;
|
|
if (batch_num > thread_max_batch_num) {
|
|
thread_max_batch_num = batch_num;
|
|
}
|
|
VLOG(3) << "ins num:" << ins_num << ", batch size:" << batch_size
|
|
<< ", batch_num:" << thread_max_batch_num;
|
|
}
|
|
#ifdef PADDLE_WITH_GLOO
|
|
auto gloo_wrapper = paddle::framework::GlooWrapper::GetInstance();
|
|
if (gloo_wrapper->Size() > 1 && !sage_mode) {
|
|
if (!gloo_wrapper->IsInitialized()) {
|
|
VLOG(0) << "GLOO is not inited";
|
|
gloo_wrapper->Init();
|
|
}
|
|
std::vector<int> thread_batch_num_vec(1, thread_max_batch_num);
|
|
auto thread_max_batch_num_vec =
|
|
gloo_wrapper->AllReduce(thread_batch_num_vec, "max");
|
|
thread_max_batch_num = thread_max_batch_num_vec[0];
|
|
VLOG(3) << "thread max batch num:" << thread_max_batch_num;
|
|
for (size_t i = 0; i < readers_.size(); i++) {
|
|
readers_[i]->SetNewBatchsize(thread_max_batch_num);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void SlotRecordDataset::DynamicAdjustReadersNum(int thread_num) {
|
|
if (thread_num_ == thread_num) {
|
|
DynamicAdjustBatchNum();
|
|
VLOG(3) << "DatasetImpl<T>::DynamicAdjustReadersNum thread_num_="
|
|
<< thread_num_ << ", thread_num_=thread_num, no need to adjust";
|
|
return;
|
|
}
|
|
VLOG(3) << "adjust readers num from " << thread_num_ << " to " << thread_num;
|
|
thread_num_ = thread_num;
|
|
std::vector<std::shared_ptr<paddle::framework::DataFeed>>().swap(readers_);
|
|
CreateReaders();
|
|
VLOG(3) << "adjust readers num done";
|
|
PrepareTrain();
|
|
}
|
|
|
|
} // namespace paddle::framework
|