Skip to content

Commit d74b2f9

Browse files
committed
Update
1 parent e2c229d commit d74b2f9

8 files changed

Lines changed: 168 additions & 43 deletions

File tree

dlib/cuda/cpu_dlib.h

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,8 @@ namespace dlib
786786
const tensor& input_tensor,
787787
const tensor& output_tensor,
788788
tensor& grad,
789-
double& loss
789+
double& loss,
790+
long ignore_index
790791
) const
791792
{
792793
DLIB_CASSERT(output_tensor.k() == 1);
@@ -796,16 +797,46 @@ namespace dlib
796797
const long batch_size = output_tensor.num_samples();
797798
const long seq_len = output_tensor.nr();
798799
const long vocab_size = output_tensor.nc();
799-
800-
// Normalization over all positions
801-
const double scale = 1.0 / (batch_size * seq_len);
802-
803-
loss = 0.0;
800+
804801
const float* out_data = output_tensor.host();
805802
const float* in_data = input_tensor.host();
806-
float* g = grad.host();
803+
float* g = grad.host();
807804

808805
std::fill(g, g + grad.size(), 0.0f);
806+
807+
long valid_tokens = 0;
808+
809+
if (ignore_index < 0)
810+
{
811+
valid_tokens = batch_size * seq_len;
812+
}
813+
else {
814+
for (long i = 0; i < batch_size; ++i)
815+
{
816+
for (long t = 0; t < seq_len; ++t)
817+
{
818+
unsigned long target_class;
819+
if (t < seq_len - 1) {
820+
target_class = static_cast<unsigned long>(
821+
in_data[tensor_index(input_tensor, i, 0, t + 1, 0)]
822+
);
823+
}
824+
else
825+
target_class = *(truth + i);
826+
827+
if (static_cast<long>(target_class) != ignore_index)
828+
valid_tokens++;
829+
}
830+
}
831+
}
832+
if (valid_tokens == 0)
833+
{
834+
loss = 0.0;
835+
return;
836+
}
837+
838+
const double scale = 1.0 / valid_tokens;
839+
loss = 0.0;
809840

810841
for (long i = 0; i < batch_size; ++i)
811842
{
@@ -825,6 +856,9 @@ namespace dlib
825856
target_class = *(truth + i);
826857
}
827858

859+
if (ignore_index >= 0 && static_cast<long>(target_class) == ignore_index)
860+
continue;
861+
828862
DLIB_CASSERT(target_class < static_cast<unsigned long>(vocab_size));
829863

830864
// Find max logit for numerical stability

dlib/cuda/cuda_dlib.cu

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3139,6 +3139,39 @@ namespace dlib
31393139

31403140
// ----------------------------------------------------------------------------------------
31413141

3142+
__global__ void _cuda_count_valid_tokens(
3143+
float* valid_count,
3144+
const unsigned long* truth,
3145+
const float* input_data,
3146+
size_t batch_size,
3147+
size_t seq_len,
3148+
long ignore_index
3149+
)
3150+
{
3151+
float count = 0.0f;
3152+
3153+
for (auto sample_idx : grid_stride_range(0, batch_size))
3154+
{
3155+
for (size_t t = 0; t < seq_len; ++t)
3156+
{
3157+
unsigned long target_class;
3158+
if (t < seq_len - 1) {
3159+
const size_t input_idx = sample_idx * seq_len + (t + 1);
3160+
target_class = static_cast<unsigned long>(input_data[input_idx]);
3161+
}
3162+
else {
3163+
target_class = truth[sample_idx];
3164+
}
3165+
3166+
if (ignore_index < 0 || static_cast<long>(target_class) != ignore_index) {
3167+
count += 1.0f;
3168+
}
3169+
}
3170+
}
3171+
3172+
warp_reduce_atomic_add(*valid_count, count);
3173+
}
3174+
31423175
__global__ void _cuda_compute_loss_cross_entropy_per_logit(
31433176
float* loss_out,
31443177
float* g,
@@ -3148,7 +3181,8 @@ namespace dlib
31483181
size_t batch_size,
31493182
size_t seq_len,
31503183
size_t vocab_size,
3151-
const float scale
3184+
float scale,
3185+
long ignore_index
31523186
)
31533187
{
31543188
float total_loss = 0;
@@ -3158,7 +3192,6 @@ namespace dlib
31583192
for (size_t t = 0; t < seq_len; ++t)
31593193
{
31603194
unsigned long target_class;
3161-
31623195
if (t < seq_len - 1) {
31633196
const size_t input_idx = sample_idx * seq_len + (t + 1);
31643197
target_class = static_cast<unsigned long>(input_data[input_idx]);
@@ -3168,7 +3201,15 @@ namespace dlib
31683201
}
31693202

31703203
const size_t base_idx = sample_idx * seq_len * vocab_size + t * vocab_size;
3171-
float max_val = out_data[base_idx + 0];
3204+
3205+
if (ignore_index >= 0 && static_cast<long>(target_class) == ignore_index) {
3206+
for (size_t c = 0; c < vocab_size; ++c) {
3207+
g[base_idx + c] = 0.0f;
3208+
}
3209+
continue;
3210+
}
3211+
3212+
float max_val = out_data[base_idx];
31723213
for (size_t c = 1; c < vocab_size; ++c)
31733214
{
31743215
max_val = ::max(max_val, out_data[base_idx + c]);
@@ -3210,7 +3251,8 @@ namespace dlib
32103251
const tensor& input_tensor,
32113252
const tensor& subnetwork_output,
32123253
tensor& gradient,
3213-
double& loss
3254+
double& loss,
3255+
long ignore_index
32143256
)
32153257
{
32163258
CHECK_CUDA(cudaMemset(gradient.device(), 0, gradient.size() * sizeof(float)));
@@ -3220,7 +3262,35 @@ namespace dlib
32203262
const long seq_len = subnetwork_output.nr();
32213263
const long vocab_size = subnetwork_output.nc();
32223264

3223-
const double scale = 1.0 / (batch_size * seq_len);
3265+
double scale;
3266+
if (ignore_index < 0)
3267+
{
3268+
scale = 1.0 / (batch_size * seq_len);
3269+
}
3270+
else {
3271+
cuda_data_void_ptr count_buf = device_global_buffer(sizeof(float));
3272+
auto valid_count_ptr = static_pointer_cast<float>(count_buf, 1);
3273+
CHECK_CUDA(cudaMemset(valid_count_ptr, 0, sizeof(float)));
3274+
3275+
launch_kernel(_cuda_count_valid_tokens, max_jobs(batch_size),
3276+
valid_count_ptr.data(),
3277+
truth_buffer.data(),
3278+
input_tensor.device(),
3279+
batch_size,
3280+
seq_len,
3281+
ignore_index
3282+
);
3283+
3284+
float valid_count;
3285+
dlib::cuda::memcpy(&valid_count, valid_count_ptr);
3286+
3287+
if (valid_count == 0) {
3288+
loss = 0.0;
3289+
return;
3290+
}
3291+
3292+
scale = 1.0 / valid_count;
3293+
}
32243294

32253295
launch_kernel(_cuda_compute_loss_cross_entropy_per_logit, max_jobs(batch_size),
32263296
loss_work_buffer.data(),
@@ -3231,7 +3301,8 @@ namespace dlib
32313301
batch_size,
32323302
seq_len,
32333303
vocab_size,
3234-
scale
3304+
static_cast<float>(scale),
3305+
ignore_index
32353306
);
32363307

32373308
float floss;

dlib/cuda/cuda_dlib.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -682,7 +682,8 @@ namespace dlib
682682
const tensor& input_tensor, // Source tokens
683683
const tensor& subnetwork_output, // Logits
684684
tensor& gradient,
685-
double& loss
685+
double& loss,
686+
long ignore_index
686687
) const
687688
{
688689
const size_t bytes_per_sample = sizeof(unsigned long);
@@ -697,7 +698,7 @@ namespace dlib
697698
}
698699

699700
auto truth_buf = static_pointer_cast<const unsigned long>(buf, subnetwork_output.num_samples());
700-
do_work(loss_buf, truth_buf, input_tensor, subnetwork_output, gradient, loss);
701+
do_work(loss_buf, truth_buf, input_tensor, subnetwork_output, gradient, loss, ignore_index);
701702
}
702703

703704
private:
@@ -707,7 +708,8 @@ namespace dlib
707708
const tensor& input_tensor,
708709
const tensor& subnetwork_output,
709710
tensor& gradient,
710-
double& loss
711+
double& loss,
712+
long ignore_index
711713
);
712714

713715
mutable cuda_data_void_ptr buf;

dlib/dnn/loss.h

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,11 @@ namespace dlib
918918
typedef unsigned long training_label_type;
919919
typedef unsigned long output_label_type;
920920

921+
loss_cross_entropy_per_logit_() : ignore_index_(-1) {}
922+
923+
void set_ignore_index(long idx) { ignore_index_ = idx; }
924+
long get_ignore_index() const { return ignore_index_; }
925+
921926
template <typename SUB_TYPE, typename label_iterator>
922927
void to_label(
923928
const tensor& input_tensor,
@@ -977,38 +982,43 @@ namespace dlib
977982

978983
double loss = 0.0;
979984
#ifdef DLIB_USE_CUDA
980-
cuda_compute(truth, input_tensor, output_tensor, grad, loss);
985+
cuda_compute(truth, input_tensor, output_tensor, grad, loss, ignore_index_);
981986
#else
982-
cpu_compute(truth, input_tensor, output_tensor, grad, loss);
987+
cpu_compute(truth, input_tensor, output_tensor, grad, loss, ignore_index_);
983988
#endif
984989
return loss;
985990
}
986991

987-
friend void serialize(const loss_cross_entropy_per_logit_&, std::ostream& out)
992+
friend void serialize(const loss_cross_entropy_per_logit_& item, std::ostream& out)
988993
{
989994
serialize("loss_cross_entropy_per_logit_", out);
995+
serialize(item.ignore_index_, out);
990996
}
991997

992-
friend void deserialize(loss_cross_entropy_per_logit_&, std::istream& in)
998+
friend void deserialize(loss_cross_entropy_per_logit_& item, std::istream& in)
993999
{
9941000
std::string version;
9951001
deserialize(version, in);
9961002
if (version != "loss_cross_entropy_per_logit_")
9971003
throw serialization_error("Unexpected version found while deserializing dlib::loss_cross_entropy_per_logit_.");
1004+
deserialize(item.ignore_index_, in);
9981005
}
9991006

1000-
friend std::ostream& operator<<(std::ostream& out, const loss_cross_entropy_per_logit_&)
1007+
friend std::ostream& operator<<(std::ostream& out, const loss_cross_entropy_per_logit_& item)
10011008
{
10021009
out << "loss_cross_entropy_per_logit";
1010+
out << " (ignore_index=" << item.ignore_index_ << ")";
10031011
return out;
10041012
}
10051013

1006-
friend void to_xml(const loss_cross_entropy_per_logit_& /*item*/, std::ostream& out)
1014+
friend void to_xml(const loss_cross_entropy_per_logit_& item, std::ostream& out)
10071015
{
1008-
out << "<loss_cross_entropy_per_logit/>\n";
1016+
out << "<loss_cross_entropy_per_logit ignore_index='" << item.ignore_index_ << "'/>\n";
10091017
}
10101018

10111019
private:
1020+
long ignore_index_;
1021+
10121022
#ifdef DLIB_USE_CUDA
10131023
cuda::compute_loss_cross_entropy_per_logit cuda_compute;
10141024
#else

examples/slm_advanced_train_ex.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ int main(int argc, char** argv)
449449
// Build and train the network
450450
using net_type = my_transformer::network_type<true>;
451451
net_type net;
452+
layer<0>(net).loss_details().set_ignore_index(tokenizer.get_special_token_id("<pad>"));
452453
cout << my_transformer::model_info::describe() << endl;
453454

454455
// Tokenizer stored with model for simplified inference

examples/slm_chatbot_ex.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ int main(int argc, char** argv)
267267
trainer.set_mini_batch_size(batch_size);
268268
trainer.set_max_num_epochs(max_epochs);
269269
trainer.set_iterations_without_progress_threshold(patience);
270-
trainer.set_synchronization_file("chkpt-" + finetuned_model, std::chrono::minutes(5));
270+
trainer.set_synchronization_file("chkpt-" + finetuned_model, std::chrono::minutes(25));
271271
trainer.be_quiet();
272272

273273
// Load tokenizer & model
@@ -282,6 +282,7 @@ int main(int argc, char** argv)
282282
cout << "Pre-trained tokenizer not found at: " << tokenizer_file << endl;
283283
return 1;
284284
}
285+
layer<0>(net).loss_details().set_ignore_index(tokenizer.get_special_token_id("<pad>"));
285286

286287
// Load Q&A datasets for fine-tuning
287288
cout << "Loading Q&A training datasets...\n";
@@ -348,10 +349,10 @@ int main(int argc, char** argv)
348349
qa_tokens.clear();
349350

350351
cout << "Applying freezing strategy...\n";
351-
set_all_learning_rate_multipliers(net, 0.1);
352-
layer<1>(net).layer_details().set_learning_rate_multiplier(1.0); // linear
353-
layer<2>(net).layer_details().set_learning_rate_multiplier(0.5); // rms_norm
354-
layer<111>(net).layer_details().set_learning_rate_multiplier(0.5); // embeddings
352+
//set_all_learning_rate_multipliers(net, 0.1);
353+
//layer<1>(net).layer_details().set_learning_rate_multiplier(1.0); // linear
354+
//layer<2>(net).layer_details().set_learning_rate_multiplier(0.5); // rms_norm
355+
//layer<111>(net).layer_details().set_learning_rate_multiplier(0.5); // embeddings
355356
cout << "Fine-tuning learning rate strategy applied.\n\n";
356357
cout << net << endl;
357358

examples/slm_mixture_of_experts_ex.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,7 @@ int main(int argc, char** argv)
792792
// Build and train the network
793793
using net_type = my_transformer::network_type<true>;
794794
net_type net;
795+
layer<0>(net).loss_details().set_ignore_index(tokenizer.get_special_token_id("<pad>"));
795796
cout << my_transformer::model_info::describe() << endl;
796797

797798
// Tokenizer stored with model for simplified inference
@@ -805,7 +806,7 @@ int main(int argc, char** argv)
805806
trainer.set_learning_rate_shrink_factor(0.1);
806807
trainer.set_mini_batch_size(batch_size);
807808
trainer.set_iterations_without_progress_threshold(patience);
808-
trainer.set_synchronization_file("chkpt-" + model_file, std::chrono::minutes(5));
809+
trainer.set_synchronization_file("chkpt-" + model_file, std::chrono::minutes(25));
809810
trainer.be_quiet();
810811
cout << net << endl << endl; // Show the model architecture
811812
cout << "Starting training...\n";

0 commit comments

Comments
 (0)