chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
@@ -0,0 +1,260 @@
// 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.
#include "paddle/phi/kernels/selected_rows/adam_kernel.h"
#include "glog/logging.h"
#include "paddle/common/flags.h"
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/tensor_utils.h"
#include "paddle/phi/core/threadpool.h"
#include "paddle/phi/kernels/funcs/adam_functors.h"
#include "paddle/phi/kernels/funcs/selected_rows_functor.h"
PD_DECLARE_int32(inner_op_parallelism);
namespace phi::sr {
template <typename T, typename Context>
void AdamDenseParamSparseGradKernel(const Context& dev_ctx,
const DenseTensor& param,
const SelectedRows& grad,
const DenseTensor& learning_rate,
const DenseTensor& moment1,
const DenseTensor& moment2,
const optional<DenseTensor>& moment2_max,
const DenseTensor& beta1_pow,
const DenseTensor& beta2_pow,
const optional<DenseTensor>& master_param
UNUSED,
const optional<DenseTensor>& skip_update,
const Scalar& beta1,
const Scalar& beta2,
const Scalar& epsilon,
bool lazy_mode,
int64_t min_row_size_to_use_multithread,
bool multi_precision UNUSED,
bool use_global_beta_pow,
bool amsgrad,
DenseTensor* param_out,
DenseTensor* moment1_out,
DenseTensor* moment2_out,
DenseTensor* moment2_max_out,
DenseTensor* beta1_pow_out,
DenseTensor* beta2_pow_out,
DenseTensor* master_param_outs UNUSED) {
VLOG(4) << "use_global_beta_pow:" << use_global_beta_pow;
bool skip_update_ = false;
if (skip_update.is_initialized()) {
PADDLE_ENFORCE_EQ(
skip_update->numel(),
1,
errors::InvalidArgument("Input(SkipUpdate) size must be 1, but get %d",
skip_update->numel()));
std::vector<bool> skip_update_vec;
TensorToVector(*skip_update, dev_ctx, &skip_update_vec);
skip_update_ = skip_update_vec[0];
}
// skip_update=true, just copy input to output, and TensorCopy will call
// mutable_data
if (skip_update_) {
VLOG(4) << "Adam skip update";
phi::Copy(dev_ctx, param, dev_ctx.GetPlace(), false, param_out);
phi::Copy(dev_ctx, moment1, dev_ctx.GetPlace(), false, moment1_out);
phi::Copy(dev_ctx, moment2, dev_ctx.GetPlace(), false, moment2_out);
if (amsgrad) {
phi::Copy(dev_ctx,
moment2_max.get(),
dev_ctx.GetPlace(),
false,
moment2_max_out);
}
if (!use_global_beta_pow) {
phi::Copy(dev_ctx, beta1_pow, dev_ctx.GetPlace(), false, beta1_pow_out);
phi::Copy(dev_ctx, beta2_pow, dev_ctx.GetPlace(), false, beta2_pow_out);
}
return;
}
T beta1_ = beta1.to<T>();
T beta2_ = beta2.to<T>();
T epsilon_ = epsilon.to<T>();
VLOG(3) << "beta1_pow.numel() : " << beta1_pow.numel();
VLOG(3) << "beta2_pow.numel() : " << beta2_pow.numel();
VLOG(3) << "param.numel(): " << param.numel();
PADDLE_ENFORCE_EQ(
beta1_pow_out->numel(),
1,
errors::InvalidArgument("beta1 pow output size should be 1, but received "
"value is:%d.",
beta1_pow_out->numel()));
PADDLE_ENFORCE_EQ(
beta2_pow_out->numel(),
1,
errors::InvalidArgument("beta2 pow output size should be 1, but received "
"value is:%d.",
beta2_pow_out->numel()));
if (grad.rows().empty()) {
VLOG(3) << "grad row size is 0!!";
return;
}
std::vector<int64_t> cpu_rows(grad.rows().begin(), grad.rows().end());
bool is_strict_sorted = true;
for (size_t i = 1; i < cpu_rows.size(); ++i) {
if (cpu_rows[i - 1] >= cpu_rows[i]) {
is_strict_sorted = false;
break;
}
}
SelectedRows tmp_grad_merge;
const SelectedRows* grad_merge_ptr = nullptr;
if (is_strict_sorted) {
grad_merge_ptr = &grad;
} else {
// merge duplicated rows if any.
// The rows of grad_merge have been sorted inside MergeAdd functor
funcs::scatter::MergeAdd<Context, T> merge_func;
merge_func(dev_ctx, grad, &tmp_grad_merge, true);
grad_merge_ptr = &tmp_grad_merge;
}
auto& grad_merge = *grad_merge_ptr;
auto& grad_tensor = grad_merge.value();
const T* grad_data = grad_tensor.template data<T>();
auto* grad_merge_rows = &grad_merge.rows();
phi::MixVector<int64_t> mixv_grad_merge_rows(grad_merge_rows);
const int64_t* rows = mixv_grad_merge_rows.Data(dev_ctx.GetPlace());
auto row_numel = grad_tensor.numel() / grad_merge.rows().size();
T lr_value = static_cast<T>(learning_rate.data<double>()[0]);
funcs::SparseAdamFunctor<T, funcs::CPUAdam> functor(
beta1_,
beta2_,
epsilon_,
beta1_pow.data<T>(),
beta2_pow.data<T>(),
moment1.data<T>(),
dev_ctx.template Alloc<T>(moment1_out),
moment2.data<T>(),
dev_ctx.template Alloc<T>(moment2_out),
amsgrad ? moment2_max.get().data<T>() : nullptr,
amsgrad ? dev_ctx.template Alloc<T>(moment2_max_out) : nullptr,
&lr_value,
grad_data,
param.data<T>(),
dev_ctx.template Alloc<T>(param_out),
rows,
row_numel,
grad_merge.rows().size(),
lazy_mode,
amsgrad);
// update beta1 and beta2
if (!use_global_beta_pow) {
dev_ctx.template Alloc<T>(beta1_pow_out)[0] =
beta1_ * beta1_pow.data<T>()[0];
dev_ctx.template Alloc<T>(beta2_pow_out)[0] =
beta2_ * beta2_pow.data<T>()[0];
}
if (lazy_mode) {
VLOG(3) << "run cpu lazy mode";
size_t row_count = grad_merge.rows().size();
std::vector<int64_t> cpu_rows(grad_merge.rows());
for (size_t row_index = 0; row_index < row_count; ++row_index) {
for (size_t offset = 0; offset < row_numel; ++offset) {
size_t i = cpu_rows[row_index] * row_numel + offset;
functor.adam_update(i, grad_data[row_index * row_numel + offset]);
}
}
}
#ifndef _WIN32
else if (FLAGS_inner_op_parallelism > 1 && // NOLINT
min_row_size_to_use_multithread > 0 &&
param.dims()[0] > min_row_size_to_use_multithread) {
VLOG(3) << "use multi thread, inner_op_parallelism="
<< FLAGS_inner_op_parallelism << " min_row_size_to_use_multithread="
<< min_row_size_to_use_multithread;
if (FLAGS_inner_op_parallelism > 10) {
VLOG(1) << "FLAGS_inner_op_parallelism " << FLAGS_inner_op_parallelism
<< " is two large!";
}
auto& grad_rows = grad_merge.rows();
std::unordered_map<size_t, int> row_id_to_grad_row_offset;
size_t param_row_count = param.numel() / row_numel;
if (param_row_count < 1000) {
VLOG(1) << "param_row_count should be larger then 1000 to use "
"multi thread, currently "
<< param_row_count;
}
for (int i = 0; i < static_cast<int>(grad_rows.size()); ++i) {
row_id_to_grad_row_offset[grad_rows[i]] = i;
}
std::vector<std::future<void>> fs;
int64_t line_in_each_thread = static_cast<int64_t>(
param_row_count / FLAGS_inner_op_parallelism + static_cast<int64_t>(1));
for (int i = 0; i < FLAGS_inner_op_parallelism; ++i) {
int64_t start = i * line_in_each_thread;
int64_t end = (i + 1) * line_in_each_thread;
if (start >= static_cast<int64_t>(param_row_count)) {
break;
}
if (end > static_cast<int64_t>(param_row_count)) {
end = static_cast<int64_t>(param_row_count);
}
fs.push_back(phi::Async([&functor,
&row_id_to_grad_row_offset,
&grad_data,
row_numel,
start,
end]() {
for (int64_t row_id = start; row_id < end; ++row_id) {
auto iter = row_id_to_grad_row_offset.find(row_id);
if (iter != row_id_to_grad_row_offset.end()) {
for (size_t row_offset = 0U; row_offset < row_numel; ++row_offset) {
functor.adam_update(
row_id * row_numel + row_offset,
grad_data[iter->second * row_numel + row_offset]);
}
} else {
for (size_t row_offset = 0U; row_offset < row_numel; ++row_offset) {
functor.adam_update(row_id * row_numel + row_offset, 0);
}
}
}
}));
}
for (auto& item : fs) item.wait();
}
#endif // !_WIN32
else { // NOLINT
functor(param.numel());
}
}
} // namespace phi::sr
PD_REGISTER_KERNEL(adam_dense_param_sparse_grad,
CPU,
ALL_LAYOUT,
phi::sr::AdamDenseParamSparseGradKernel,
float,
double) {}
@@ -0,0 +1,147 @@
// 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.
#include "paddle/phi/kernels/selected_rows/adamw_kernel.h"
#include "glog/logging.h"
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/core/tensor_utils.h"
#include "paddle/phi/kernels/adam_kernel.h"
#include "paddle/phi/kernels/funcs/adam_functors.h"
#include "paddle/phi/kernels/selected_rows/adam_kernel.h"
namespace phi::sr {
template <typename T, typename Context>
void AdamwDenseParamSparseGradKernel(const Context& dev_ctx,
const DenseTensor& param,
const SelectedRows& grad,
const DenseTensor& learning_rate,
const DenseTensor& moment1,
const DenseTensor& moment2,
const optional<DenseTensor>& moment2_max,
const DenseTensor& beta1_pow,
const DenseTensor& beta2_pow,
const optional<DenseTensor>& master_param,
const optional<DenseTensor>& skip_update,
const Scalar& beta1,
const Scalar& beta2,
const Scalar& epsilon,
float lr_ratio,
float coeff,
bool with_decay,
bool lazy_mode,
int64_t min_row_size_to_use_multithread,
bool multi_precision,
bool use_global_beta_pow,
bool amsgrad,
DenseTensor* param_out,
DenseTensor* moment1_out,
DenseTensor* moment2_out,
DenseTensor* moment2_max_out,
DenseTensor* beta1_pow_out,
DenseTensor* beta2_pow_out,
DenseTensor* master_param_outs) {
bool skip_update_ = false;
if (skip_update.is_initialized()) {
PADDLE_ENFORCE_EQ(
skip_update->numel(),
1,
errors::InvalidArgument("Input(SkipUpdate) size must be 1, but get %d",
skip_update->numel()));
std::vector<bool> skip_update_vec;
TensorToVector(*skip_update, dev_ctx, &skip_update_vec);
skip_update_ = skip_update_vec[0];
}
VLOG(3) << "Skip update" << skip_update_;
if (skip_update_ || !with_decay) {
AdamDenseParamSparseGradKernel<T, Context>(dev_ctx,
param,
grad,
learning_rate,
moment1,
moment2,
moment2_max,
beta1_pow,
beta2_pow,
master_param,
skip_update,
beta1,
beta2,
epsilon,
lazy_mode,
min_row_size_to_use_multithread,
multi_precision,
use_global_beta_pow,
amsgrad,
param_out,
moment1_out,
moment2_out,
moment2_max_out,
beta1_pow_out,
beta2_pow_out,
master_param_outs);
return;
}
auto* param_ =
master_param.is_initialized() ? master_param.get_ptr() : &param;
T coeff_ = static_cast<T>(coeff);
T lr_ratio_ = static_cast<T>(lr_ratio);
funcs::AdamWFunctor<T, funcs::CPUAdamW> functor(
coeff_,
lr_ratio_,
learning_rate.data<T>(),
const_cast<T*>(param_->data<T>()));
functor(param_->numel());
AdamDenseParamSparseGradKernel<T, Context>(dev_ctx,
param,
grad,
learning_rate,
moment1,
moment2,
moment2_max,
beta1_pow,
beta2_pow,
master_param,
skip_update,
beta1,
beta2,
epsilon,
lazy_mode,
min_row_size_to_use_multithread,
multi_precision,
use_global_beta_pow,
amsgrad,
param_out,
moment1_out,
moment2_out,
moment2_max_out,
beta1_pow_out,
beta2_pow_out,
master_param_outs);
}
} // namespace phi::sr
PD_REGISTER_KERNEL(adamw_dense_param_sparse_grad,
CPU,
ALL_LAYOUT,
phi::sr::AdamwDenseParamSparseGradKernel,
float,
double) {}
@@ -0,0 +1,25 @@
// 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.
#include "paddle/phi/kernels/selected_rows/impl/add_n_kernel_impl.h"
PD_REGISTER_KERNEL(add_n_sr,
CPU,
ALL_LAYOUT,
phi::sr::AddNKernel,
float,
double,
int,
phi::bfloat16,
int64_t) {}
@@ -0,0 +1,22 @@
// 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.
#include "paddle/phi/kernels/selected_rows/clip_by_norm_kernel.h"
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/selected_rows/impl/clip_by_norm_kernel_impl.h"
PD_REGISTER_KERNEL(
clip_by_norm_sr, CPU, ALL_LAYOUT, phi::sr::ClipByNormKernel, float) {}
@@ -0,0 +1,28 @@
// 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.
#include "paddle/phi/kernels/selected_rows/clip_kernel.h"
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/selected_rows/impl/clip_kernel_impl.h"
PD_REGISTER_KERNEL(clip_sr,
CPU,
ALL_LAYOUT,
phi::sr::ClipSparseKernel,
float,
double,
int,
int64_t) {}
@@ -0,0 +1,19 @@
// Copyright (c) 2024 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/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/selected_rows/impl/dgc_clip_by_norm_kernel_impl.h"
PD_REGISTER_KERNEL(
dgc_clip_by_norm_sr, CPU, ALL_LAYOUT, phi::sr::DGCClipByNormKernel, float) {
}
@@ -0,0 +1,18 @@
// Copyright (c) 2024 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/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/selected_rows/impl/ftrl_kernel_impl.h"
PD_REGISTER_KERNEL(ftrl_sr, CPU, ALL_LAYOUT, phi::sr::FTRLOpKernel, float) {}
@@ -0,0 +1,24 @@
// Copyright (c) 2024 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/phi/kernels/selected_rows/impl/get_tensor_from_selected_rows_kernel_impl.h"
PD_REGISTER_KERNEL(get_tensor_from_selected_rows,
CPU,
ALL_LAYOUT,
phi::sr::GetTensorFromSelectedRowsKernel,
float,
double,
int,
int64_t) {}
@@ -0,0 +1,21 @@
// 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.
#include "paddle/phi/kernels/selected_rows/lamb_kernel.h"
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/selected_rows/impl/lamb_kernel_impl.h"
PD_REGISTER_KERNEL(
lamb_sr, CPU, ALL_LAYOUT, phi::sr::LambKernel, float, double) {}
@@ -0,0 +1,18 @@
// Copyright (c) 2024 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/phi/kernels/selected_rows/impl/load_kernel_impl.h"
PD_REGISTER_KERNEL(
load_sr, CPU, ALL_LAYOUT, phi::sr::LoadSelectedRowsKernel, float) {}
@@ -0,0 +1,161 @@
// Copyright (c) 2024 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 <string>
#include <vector>
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/enforce.h"
#include "paddle/phi/kernels/funcs/blas/blas.h"
#include "paddle/phi/kernels/funcs/eigen/common.h"
#include "paddle/phi/kernels/funcs/selected_rows_functor.h"
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
namespace phi {
namespace sr {
constexpr int64_t kNoPadding = -1;
template <typename T, typename Context>
void LookupTableGradKernel(const Context &dev_ctx,
const SelectedRows &w,
const DenseTensor &ids_in,
const DenseTensor &out_grad,
bool is_sparse,
int64_t padding_idx,
bool is_test,
DenseTensor *w_grad) {
DDim table_dim;
auto *table_t = &w;
table_dim = table_t->value().dims();
// Since paddings are not trainable and fixed in forward, the gradient of
// paddings makes no sense and we don't deal with it in backward.
auto *ids = &ids_in;
auto *d_output = &out_grad;
auto *d_table = w_grad;
auto *ids_data = ids->data<int64_t>();
int64_t N = table_dim[0];
int64_t D = table_dim[1];
auto *d_output_data = d_output->data<T>();
auto *d_table_data = dev_ctx.template Alloc<T>(d_table);
memset(d_table_data, 0, d_table->numel() * sizeof(T));
for (int64_t i = 0; i < ids->numel(); ++i) {
if (padding_idx != kNoPadding && ids_data[i] == padding_idx) {
// the gradient of padding_idx should be 0, already done by memset, so
// do nothing.
} else {
PADDLE_ENFORCE_LT(
ids_data[i],
N,
common::errors::InvalidArgument(
"Variable value (input) of OP(lookup_table_grad) "
"expected >= 0 and < %ld, but got %ld. Please check input "
"value.",
N,
ids_data[i]));
PADDLE_ENFORCE_GE(
ids_data[i],
0,
common::errors::InvalidArgument(
"Variable value (input) of OP(lookup_table_grad) "
"expected >= 0 and < %ld, but got %ld. Please check input "
"value.",
N,
ids_data[i]));
for (int j = 0; j < D; ++j) {
d_table_data[ids_data[i] * D + j] += d_output_data[i * D + j];
}
}
}
}
template <typename T, typename Context>
void LookupTableSparseGradKernel(const Context &dev_ctx,
const SelectedRows &w,
const DenseTensor &ids_in,
const DenseTensor &out_grad,
bool is_sparse,
int64_t padding_idx,
bool is_test,
SelectedRows *w_grad) {
DDim table_dim;
auto *table_t = &w;
table_dim = table_t->value().dims();
// Since paddings are not trainable and fixed in forward, the gradient of
// paddings makes no sense and we don't deal with it in backward.
auto *ids = &ids_in;
auto *d_output = &out_grad;
auto *d_table = w_grad;
auto *ids_data = ids->data<int64_t>();
int64_t ids_num = ids->numel();
std::vector<int64_t> new_rows;
new_rows.resize(ids_num);
std::memcpy(&new_rows[0], ids_data, ids_num * sizeof(int64_t));
d_table->set_rows(new_rows);
auto *d_table_value = d_table->mutable_value();
d_table_value->Resize({ids_num, table_dim[1]});
dev_ctx.template Alloc<T>(d_table_value);
d_table->set_height(table_dim[0]);
auto *d_output_data = d_output->data<T>();
auto *d_table_data = d_table_value->data<T>();
auto d_output_dims = d_output->dims();
auto d_output_dims_2d =
common::flatten_to_2d(d_output_dims, d_output_dims.size() - 1);
PADDLE_ENFORCE_EQ(d_table_value->dims(),
d_output_dims_2d,
common::errors::InvalidArgument(
"ShapeError: The shape of lookup_table@Grad and "
"output@Grad should be same. "
"But received lookup_table@Grad's shape = [%s], "
"output@Grad's shape = [%s].",
d_table_value->dims(),
d_output_dims_2d));
memcpy(d_table_data, d_output_data, sizeof(T) * d_output->numel());
}
} // namespace sr
} // namespace phi
PD_REGISTER_KERNEL(lookup_table_grad_sr,
CPU,
ALL_LAYOUT,
phi::sr::LookupTableGradKernel,
float,
double,
phi::bfloat16) {}
PD_REGISTER_KERNEL(lookup_table_sparse_grad_sr,
CPU,
ALL_LAYOUT,
phi::sr::LookupTableSparseGradKernel,
float,
double,
phi::bfloat16) {}
@@ -0,0 +1,131 @@
// Copyright (c) 2024 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 <string>
#include <vector>
#include "paddle/phi/core/dense_tensor.h"
#include "paddle/phi/core/enforce.h"
#include "paddle/phi/kernels/funcs/blas/blas.h"
#include "paddle/phi/kernels/funcs/eigen/common.h"
#include "paddle/phi/kernels/funcs/selected_rows_functor.h"
#include "paddle/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/kernel_registry.h"
namespace phi {
namespace sr {
constexpr int64_t kNoPadding = -1;
template <typename T, typename Context>
void LookupTableKernel(const Context &dev_ctx,
const SelectedRows &w,
const DenseTensor &ids_in,
bool is_sparse,
bool is_distributed UNUSED,
int64_t padding_idx,
bool remote_prefetch UNUSED,
const std::string &entry_config UNUSED,
bool is_test,
const std::string &entry UNUSED,
const std::string &table_class UNUSED,
const std::vector<std::string> &table_names UNUSED,
int trainer_id UNUSED,
bool grad_inplace UNUSED,
const std::vector<std::string> &epmap UNUSED,
const std::vector<int64_t> &height_sections UNUSED,
SelectedRows *out) {
auto *ids_t = &ids_in; // int tensor
auto *output_t = out; // float tensor
int64_t *ids = const_cast<int64_t *>(ids_t->data<int64_t>());
int64_t ids_numel = ids_t->numel();
const auto &table_t = w;
int64_t row_width = table_t.value().dims()[1];
const auto *table = table_t.value().data<T>();
auto *output = dev_ctx.template Alloc<T>(output_t);
auto input_data_type = table_t.value().dtype();
for (int64_t i = 0; i < ids_numel; ++i) {
if (padding_idx != kNoPadding && ids[i] == padding_idx) {
memset(output + i * row_width, 0, row_width * sizeof(T));
} else {
PADDLE_ENFORCE_GE(ids[i],
0,
common::errors::InvalidArgument(
"Variable value (input) of OP(lookup_table) "
"expected >= 0. But received %ld",
ids[i]));
if (is_test) {
auto id_index = table_t.GetIndexFromId(ids[i]);
if (id_index != -1) {
if (input_data_type == phi::DataType::INT8 ||
input_data_type == phi::DataType::INT16 ||
input_data_type == phi::DataType::BFLOAT16) {
memcpy(output + i * row_width,
table + id_index * row_width,
row_width * sizeof(T));
} else {
auto blas = funcs::GetBlas<CPUContext, T>(dev_ctx);
blas.VCOPY(row_width,
table + id_index * row_width,
output + i * row_width);
}
} else {
memset(output + i * row_width, 0, row_width * sizeof(T));
}
} else {
auto id_index = table_t.Index(ids[i]);
PADDLE_ENFORCE_GE(ids[i],
0,
common::errors::InvalidArgument(
"Variable value (input) of OP(lookup_table) "
"expected >= 0. But received %ld",
ids[i]));
PADDLE_ENFORCE_GE(
id_index,
0,
common::errors::InvalidArgument(
"the input key should be exists. But received %d.", id_index));
if (input_data_type == phi::DataType::INT8 ||
input_data_type == phi::DataType::INT16 ||
input_data_type == phi::DataType::BFLOAT16) {
memcpy(output + i * row_width,
table + id_index * row_width,
row_width * sizeof(T));
} else {
auto blas = funcs::GetBlas<CPUContext, T>(dev_ctx);
blas.VCOPY(
row_width, table + id_index * row_width, output + i * row_width);
}
}
}
}
}
} // namespace sr
} // namespace phi
PD_REGISTER_KERNEL(lookup_table_sr,
CPU,
ALL_LAYOUT,
phi::sr::LookupTableKernel,
float,
double,
int8_t,
int16_t,
phi::bfloat16) {}
@@ -0,0 +1,220 @@
// Copyright (c) 2024 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 <math.h>
#include <iterator>
#include <random>
#include <set>
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/funcs/eigen/common.h"
#include "paddle/phi/kernels/funcs/math/sampler.h"
#include "paddle/phi/kernels/funcs/selected_rows_functor.h"
#include "paddle/utils/optional.h"
namespace phi {
namespace sr {
using Sampler = phi::math::Sampler;
template <typename T, typename Context>
void NCEGradKernel(const Context &dev_ctx,
const DenseTensor &input_in,
const DenseTensor &label_in,
const optional<DenseTensor> &bias_in,
const DenseTensor &weight_in,
const DenseTensor &sample_logits_in,
const DenseTensor &sample_labels_in,
const optional<DenseTensor> &sample_weight_in,
const optional<DenseTensor> &custom_dist_probs,
const optional<DenseTensor> &custom_dist_alias,
const optional<DenseTensor> &custom_dist_alias_probs,
const DenseTensor &cost_grad,
int num_total_classes,
const std::vector<int> &custom_neg_classes,
int num_neg_samples,
int sampler_in,
int seed,
bool is_sparse,
bool remote_prefetch,
bool is_test,
DenseTensor *input_grad,
DenseTensor *bias_grad,
SelectedRows *weight_grad) {
auto d_out = &cost_grad;
const T *d_out_data = d_out->data<T>();
auto label = &label_in;
auto sample_out = &sample_logits_in;
const T *sample_out_data = sample_out->data<T>();
auto sample_labels = &sample_labels_in;
const int64_t *sample_labels_data = sample_labels->data<int64_t>();
auto sample_weight = sample_weight_in.get_ptr();
const T *sample_weight_data = nullptr;
if (sample_weight != nullptr) {
sample_weight_data = sample_weight->data<T>();
}
int num_true_class = 1;
if (label != nullptr) {
num_true_class = label->dims()[1];
}
int sampler_type = sampler_in;
Sampler *sampler;
switch (sampler_type) {
case 0: {
sampler = new phi::math::UniformSampler(num_total_classes - 1, seed);
break;
}
case 1: {
sampler = new phi::math::LogUniformSampler(num_total_classes - 1, seed);
break;
}
case 2: {
auto dist_probs = custom_dist_probs.get_ptr();
auto dist_alias = custom_dist_alias.get_ptr();
auto dist_alias_probs = custom_dist_alias_probs.get_ptr();
PADDLE_ENFORCE_EQ(
dist_probs->numel(),
num_total_classes,
common::errors::InvalidArgument(
"ShapeError: The number of elements in Input(CustomDistProbs) "
"should be equal to the number of total classes. But Received: "
"Input(CustomDistProbs).numel() = %d, Attr(num_total_classes) "
"= %d.",
dist_probs->numel(),
num_total_classes));
PADDLE_ENFORCE_EQ(
dist_alias->numel(),
num_total_classes,
common::errors::InvalidArgument(
"ShapeError: The number of elements in Input(CustomDistAlias) "
"should be equal to the number of total classes. But Received: "
"Input(CustomDistAlias).numel() = %d, Attr(num_total_classes) "
"= %d.",
dist_alias->numel(),
num_total_classes));
PADDLE_ENFORCE_EQ(
dist_alias_probs->numel(),
num_total_classes,
common::errors::InvalidArgument(
"ShapeError: The number of elements in "
"Input(CustomDistAliasProbs) "
"should be equal to the number of total classes. But Received: "
"Input(CustomDistAliasProbs).numel() = %d, "
"Attr(num_total_classes) = %d.",
dist_alias_probs->numel(),
num_total_classes));
const float *probs_data = dist_probs->data<float>();
const int *alias_data = dist_alias->data<int>();
const float *alias_probs_data = dist_alias_probs->data<float>();
sampler = new phi::math::CustomSampler(num_total_classes - 1,
probs_data,
alias_data,
alias_probs_data,
seed);
break;
}
default: {
PADDLE_THROW(common::errors::InvalidArgument(
"Unsupported SamplerType. SamplerType should be 0: Uniform, "
"1: LogUniform or 2: CustomDist. Received SamplerType: %d",
sampler_type));
}
}
// T b = 1. / num_total_classes * num_neg_samples;
DenseTensor sample_grad; // tmp tensor
sample_grad.Resize(sample_labels->dims());
T *sample_grad_data = dev_ctx.template Alloc<T>(&sample_grad);
// backward cost
for (int64_t i = 0; i < sample_labels->numel(); ++i) {
int64_t label_idx = i % sample_labels->dims()[1];
int64_t sample_idx = i / sample_labels->dims()[1];
float b = sampler->Probability(sample_labels_data[i]) * num_neg_samples;
T o = sample_out_data[i];
T w = sample_weight == nullptr ? 1 : sample_weight_data[sample_idx];
sample_grad_data[i] = label_idx < num_true_class
? w * (b / (o + b)) * (o - 1)
: w * (o * (1 - o) / (o + b));
sample_grad_data[i] *= d_out_data[sample_idx];
}
// get d_bias
auto d_bias = bias_grad;
if (d_bias != nullptr) {
T *d_bias_data = dev_ctx.template Alloc<T>(d_bias);
std::fill(d_bias_data, d_bias_data + d_bias->numel(), 0.0);
for (int64_t i = 0; i < sample_labels->numel(); ++i) {
d_bias_data[sample_labels_data[i]] += sample_grad_data[i];
}
}
if (!is_sparse) {
PADDLE_THROW(
common::errors::InvalidArgument("The parameter weight_grad of a NCE_OP "
"must be DenseTensor"));
} else {
std::vector<int64_t> labels;
for (int64_t i = 0; i < sample_labels->numel(); ++i) {
labels.push_back(sample_labels_data[i]);
}
std::set<T> st(labels.begin(), labels.end());
labels.assign(st.begin(), st.end());
DDim table_dim = weight_in.dims();
auto d_w = weight_grad;
d_w->set_rows(labels);
d_w->set_height(table_dim[0]);
auto *d_table_value = d_w->mutable_value();
d_table_value->Resize({static_cast<int64_t>(labels.size()), table_dim[1]});
auto d_w_data = dev_ctx.template Alloc<T>(d_table_value);
std::fill(d_w_data, d_w_data + d_table_value->numel(), 0.0);
auto d_w_matrix = EigenMatrix<T>::From(*d_table_value);
auto x_matrix = EigenMatrix<T>::From(input_in);
for (int64_t i = 0; i < sample_labels->numel(); ++i) {
d_w_matrix.chip(d_w->Index(sample_labels_data[i]), 0) +=
x_matrix.chip(static_cast<int>(i / sample_labels->dims()[1]), 0) *
sample_grad_data[i];
}
}
// get d_x
auto d_x = input_grad;
if (d_x != nullptr) {
auto *d_x_data = dev_ctx.template Alloc<T>(d_x);
std::fill(d_x_data, d_x_data + d_x->numel(), 0.0);
auto d_x_matrix = EigenMatrix<T>::From(*d_x);
auto w_matrix = EigenMatrix<T>::From(weight_in);
for (int64_t i = 0; i < sample_labels->numel(); ++i) {
d_x_matrix.chip(static_cast<int>(i / sample_labels->dims()[1]), 0) +=
w_matrix.chip(sample_labels_data[i], 0) * sample_grad_data[i];
}
}
delete sampler;
}
} // namespace sr
} // namespace phi
PD_REGISTER_KERNEL(
nce_sr_grad, CPU, ALL_LAYOUT, phi::sr::NCEGradKernel, float, double) {}
@@ -0,0 +1,31 @@
// Copyright (c) 2024 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/phi/kernels/selected_rows/impl/save_kernel_impl.h"
PD_REGISTER_KERNEL(save_sr,
CPU,
ALL_LAYOUT,
phi::SaveSelectedRowsKernel,
float,
double,
int,
uint8_t,
int8_t,
int16_t,
int64_t,
phi::float16,
phi::bfloat16) {
kernel->InputAt(0).SetBackend(phi::Backend::ALL_BACKEND);
}
@@ -0,0 +1,29 @@
// Copyright (c) 2024 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/phi/common/data_type.h"
#include "paddle/phi/kernels/selected_rows/impl/share_data_kernel_impl.h"
PD_REGISTER_KERNEL(share_data_sr,
CPU,
ALL_LAYOUT,
phi::sr::ShareDataKernel,
bool,
int,
int8_t,
uint8_t,
int64_t,
float,
double,
phi::float16) {}
@@ -0,0 +1,77 @@
// Copyright (c) 2024 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/phi/backends/cpu/cpu_context.h"
#include "paddle/phi/core/enforce.h"
#include "paddle/phi/core/kernel_registry.h"
#include "paddle/phi/kernels/funcs/uniform_random_functor.h"
namespace phi {
namespace sr {
template <typename T, typename Context>
void CPUUniformRandomKernel(const Context& dev_ctx,
const SelectedRows& input,
const std::vector<int>& shape,
int input_dim_idx,
int output_dim_idx,
float min,
float max,
int seed,
int diag_num,
int diag_step,
float diag_val,
DataType dtype UNUSED,
SelectedRows* out) {
out->set_rows(input.rows());
out->set_height(input.height());
DenseTensor* tensor = out->mutable_value();
T* data = dev_ctx.template Alloc<T>(tensor);
int64_t size = tensor->numel();
funcs::UniformRealDistribution<T>(
data, size, min, max, static_cast<unsigned int>(seed));
unsigned int diag_num_tmp = static_cast<unsigned int>(diag_num);
unsigned int diag_step_tmp = static_cast<unsigned int>(diag_step);
auto diag_val_tmp = static_cast<T>(diag_val);
if (diag_num_tmp > 0) {
PADDLE_ENFORCE_GT(
size,
(diag_num_tmp - 1) * (diag_step_tmp + 1),
common::errors::InvalidArgument(
"ShapeInvalid: the diagonal's elements is equal (num-1) "
"* (step-1) with num %d, step %d,"
"It should be smaller than %d, but received %d",
diag_num_tmp,
diag_step_tmp,
(diag_num_tmp - 1) * (diag_step_tmp + 1),
size));
for (int64_t i = 0; i < diag_num_tmp; ++i) {
int64_t pos = i * diag_step_tmp + i;
data[pos] = diag_val_tmp;
}
}
}
} // namespace sr
} // namespace phi
PD_REGISTER_KERNEL(uniform_random_batch_size_like_sr,
CPU,
ALL_LAYOUT,
phi::sr::CPUUniformRandomKernel,
float,
double,
phi::bfloat16) {}