| 172 | } |
| 173 | |
| 174 | std::vector<Batch> |
| 175 | rebatch_input(const std::vector<Example>& examples, |
| 176 | size_t max_batch_size, |
| 177 | BatchType batch_type) { |
| 178 | if (examples.empty()) |
| 179 | return {}; |
| 180 | |
| 181 | const size_t global_batch_size = examples.size(); |
| 182 | if (max_batch_size == 0) { |
| 183 | max_batch_size = global_batch_size; |
| 184 | batch_type = BatchType::Examples; |
| 185 | } |
| 186 | |
| 187 | // Sorting the source inputs from the longest to the shortest has 2 benefits: |
| 188 | // |
| 189 | // 1. When max_batch_size is smaller that the number of inputs, we prefer translating |
| 190 | // together sentences that have a similar length for improved efficiency. |
| 191 | // 2. Decoding functions remove finished translations from the batch. On CPU, arrays are |
| 192 | // updated in place so it is more efficient to remove content at the end. Shorter sentences |
| 193 | // are more likely to finish first so we sort the batch accordingly. |
| 194 | std::vector<size_t> example_index(global_batch_size); |
| 195 | std::iota(example_index.begin(), example_index.end(), 0); |
| 196 | std::sort(example_index.begin(), example_index.end(), |
| 197 | [&examples](size_t i1, size_t i2) { |
| 198 | return examples[i1].length() > examples[i2].length(); |
| 199 | }); |
| 200 | |
| 201 | std::vector<Batch> batches; |
| 202 | if (example_index.empty()) |
| 203 | return batches; |
| 204 | batches.reserve(example_index.size()); |
| 205 | |
| 206 | VectorReader batch_reader(index_vector(examples, example_index)); |
| 207 | |
| 208 | for (size_t offset = 0;;) { |
| 209 | // the batch size increment per example is always fixed because padding is required |
| 210 | auto examples_part = batch_reader.get_next(max_batch_size, batch_type, true); |
| 211 | if (examples_part.empty()) |
| 212 | break; |
| 213 | |
| 214 | const size_t batch_size = examples_part.size(); |
| 215 | |
| 216 | Batch batch; |
| 217 | batch.examples = std::move(examples_part); |
| 218 | batch.example_index.insert(batch.example_index.begin(), |
| 219 | example_index.begin() + offset, |
| 220 | example_index.begin() + offset + batch_size); |
| 221 | offset += batch_size; |
| 222 | |
| 223 | batches.emplace_back(std::move(batch)); |
| 224 | } |
| 225 | |
| 226 | return batches; |
| 227 | } |
| 228 | |
| 229 | } |