Files
2026-07-13 13:24:13 +08:00

167 lines
4.8 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Copyright 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*/
#include <torch/extension.h> // @manual=//caffe2:torch_extension
#include <algorithm>
namespace {
template <typename T>
void exclusiveCumprod(
const T* p_choose,
T* cumprod_1mp,
uint32_t bsz,
uint32_t tgt_len,
uint32_t src_len) {
// cumprod_1mp = 1 - p_choose
for (uint32_t b = 0; b < bsz; b++) {
for (uint32_t tgt = 0; tgt < tgt_len; tgt++) {
for (uint32_t src = 0; src < src_len; src++) {
uint32_t idx = b * tgt_len * src_len + tgt * src_len + src;
cumprod_1mp[idx] = 1 - p_choose[idx];
}
}
}
// Implementing exclusive cumprod in the innermost dimension
// cumprod_1mp = cumprod(1 - p_choose)
// There is cumprod in pytorch, however there is no exclusive mode.
// cumprod(x) = [x1, x1x2, x2x3x4, ..., prod_{i=1}^n x_i]
// exclusive means
// cumprod(x) = [1, x1, x1x2, x1x2x3, ..., prod_{i=1}^{n-1} x_i]
for (uint32_t b = 0; b < bsz; b++) {
for (uint32_t tgt = 0; tgt < tgt_len; tgt++) {
uint32_t idx_offset = b * tgt_len * src_len + tgt * src_len;
T prev = cumprod_1mp[idx_offset];
// index [b][tgt][0]
cumprod_1mp[idx_offset] = (T)1.0;
T curr;
for (uint32_t src = 1; src < src_len; src++) {
uint32_t idx = idx_offset + src;
curr = cumprod_1mp[idx];
cumprod_1mp[idx] = cumprod_1mp[idx - 1] * prev;
prev = curr;
}
}
}
}
template <typename T>
void clamp(
const T* cumprod_1mp,
T* cumprod_1mp_clamp,
uint32_t bsz,
uint32_t tgt_len,
uint32_t src_len,
T min_val,
T max_val) {
for (uint32_t b = 0; b < bsz; b++) {
for (uint32_t tgt = 0; tgt < tgt_len; tgt++) {
for (uint32_t src = 0; src < src_len; src++) {
uint32_t idx = b * tgt_len * src_len + tgt * src_len + src;
if (cumprod_1mp[idx] < min_val) {
cumprod_1mp_clamp[idx] = min_val;
} else if (cumprod_1mp[idx] > max_val) {
cumprod_1mp_clamp[idx] = max_val;
} else {
cumprod_1mp_clamp[idx] = cumprod_1mp[idx];
}
}
}
}
}
template <typename T>
void alignmentTrainCPUImpl(
const T* p_choose,
T* alpha,
uint32_t bsz,
uint32_t tgt_len,
uint32_t src_len,
float eps) {
// p_choose: bsz , tgt_len, src_len
// cumprod_1mp: bsz , tgt_len, src_len
// cumprod_1mp_clamp : bsz, tgt_len, src_len
// alpha: bsz + 1, tgt_len, src_len
uint32_t elements = bsz * tgt_len * src_len;
T* cumprod_1mp = new T[elements];
T* cumprod_1mp_clamp = new T[elements];
exclusiveCumprod<T>(p_choose, cumprod_1mp, bsz, tgt_len, src_len);
clamp<T>(
cumprod_1mp, cumprod_1mp_clamp, bsz, tgt_len, src_len, (T)eps, (T)1.0);
// ai = p_i * cumprod(1 pi) * cumsum(a_i / cumprod(1 pi))
// Initialize alpha [:, 0, 0]
for (uint32_t b = 0; b < bsz; b++) {
alpha[b * tgt_len * src_len] = 1.0;
}
for (uint32_t tgt = 0; tgt < tgt_len; tgt++) {
for (uint32_t b = 0; b < bsz; b++) {
uint32_t alpha_idx, inout_idx;
T prev_scan = 0, curr_scan, out;
for (uint32_t src = 0; src < src_len; src++) {
// Apply scan/cumsum
if (tgt == 0) {
// alpha index is [b][tgt][src]
alpha_idx = b * tgt_len * src_len + src;
} else {
// alpha index is [b][tgt-1][src]
alpha_idx = b * tgt_len * src_len + (tgt - 1) * src_len + src;
}
// input index is [b][tgt][src]
inout_idx = b * tgt_len * src_len + tgt * src_len + src;
curr_scan = prev_scan + alpha[alpha_idx] / cumprod_1mp_clamp[inout_idx];
out = curr_scan * p_choose[inout_idx] * cumprod_1mp[inout_idx];
alpha[inout_idx] = std::min<T>(std::max<T>(out, 0), 1.0);
prev_scan = curr_scan;
}
}
}
free(cumprod_1mp);
free(cumprod_1mp_clamp);
}
void alignmentTrainCPU(
const torch::Tensor& p_choose,
torch::Tensor& alpha,
float eps) {
uint32_t bsz = p_choose.size(0);
uint32_t tgt_len = p_choose.size(1);
uint32_t src_len = p_choose.size(2);
AT_DISPATCH_FLOATING_TYPES_AND2(
torch::ScalarType::Half,
torch::ScalarType::BFloat16,
p_choose.scalar_type(),
"alignmentCPUImpl",
[&]() {
alignmentTrainCPUImpl<scalar_t>(
p_choose.data_ptr<scalar_t>(),
alpha.data_ptr<scalar_t>(),
bsz,
tgt_len,
src_len,
eps);
});
}
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
m.def(
"alignment_train_cpu",
&alignmentTrainCPU,
"expected_alignment_from_p_choose (CPU)");
}
} // namespace