|
3 | 3 |
|
4 | 4 | namespace infinicore::test { |
5 | 5 |
|
| 6 | +// Helper function to format shape for logging |
| 7 | +inline std::string formatShape(const std::vector<size_t> &shape) { |
| 8 | + std::ostringstream oss; |
| 9 | + oss << "["; |
| 10 | + for (size_t i = 0; i < shape.size(); ++i) { |
| 11 | + if (i > 0) { |
| 12 | + oss << ", "; |
| 13 | + } |
| 14 | + oss << shape[i]; |
| 15 | + } |
| 16 | + oss << "]"; |
| 17 | + return oss.str(); |
| 18 | +} |
| 19 | + |
6 | 20 | // Test 1: Basic module operations (creation, parameters, state_dict, load_state_dict) |
7 | 21 | TestResult NNModuleTest::testBasicModuleCreation() { |
8 | 22 | return measureTime("BasicModuleOperations", [this]() { |
@@ -115,6 +129,174 @@ TestResult NNModuleTest::testBasicModuleCreation() { |
115 | 129 | }); |
116 | 130 | } |
117 | 131 |
|
| 132 | +TestResult NNModuleTest::testTensorParallelParameters() { |
| 133 | + return measureTime("TensorParallelParameters", [this]() { |
| 134 | + try { |
| 135 | + spdlog::info("=========================================="); |
| 136 | + spdlog::info("Testing Tensor Parallel Parameters"); |
| 137 | + spdlog::info("=========================================="); |
| 138 | + |
| 139 | + auto device = infinicore::context::getDevice(); |
| 140 | + |
| 141 | + spdlog::info("Test Tensor Parallel Parameter"); |
| 142 | + // Case 1: Partition along dimension 0 (row-wise partitioning) |
| 143 | + infinicore::nn::Parameter param_dim0({8, 4}, infinicore::DataType::F32, device, 0, 0, 2); |
| 144 | + if (param_dim0->shape() != std::vector<size_t>({4, 4})) { |
| 145 | + spdlog::error("TP dim0: Expected shape [4, 4], got [{}]", formatShape(param_dim0->shape())); |
| 146 | + return false; |
| 147 | + } |
| 148 | + spdlog::info("✓ TP dim0 parameter created with correct partitioned shape"); |
| 149 | + // Case 2: Partition along dimension 1 (column-wise partitioning) |
| 150 | + infinicore::nn::Parameter param_dim1({8, 4}, infinicore::DataType::F32, device, 1, 0, 2); |
| 151 | + if (param_dim1->shape() != std::vector<size_t>({8, 2})) { |
| 152 | + spdlog::error("TP dim1: Expected shape [8, 2], got [{}]", formatShape(param_dim1->shape())); |
| 153 | + return false; |
| 154 | + } |
| 155 | + spdlog::info("✓ TP dim1 parameter created with correct partitioned shape"); |
| 156 | + spdlog::info("✓ Parameter creation with tensor parallelism passed"); |
| 157 | + |
| 158 | + spdlog::info("Test Tensor Parallel Linear Module"); |
| 159 | + auto w_data = std::vector<float>(32 * 64); |
| 160 | + auto b_data = std::vector<float>(32); |
| 161 | + for (size_t i = 0; i < 32; ++i) { |
| 162 | + for (size_t j = 0; j < 64; ++j) { |
| 163 | + w_data[i * 64 + j] = static_cast<float>(j); |
| 164 | + } |
| 165 | + b_data[i] = static_cast<float>(i); |
| 166 | + } |
| 167 | + { |
| 168 | + spdlog::info("Test tp_size=4 tp_dim=0"); |
| 169 | + Size tp_size = 4; |
| 170 | + Size tp_dim = 0; |
| 171 | + std::vector<std::unique_ptr<MockLinearModule>> tp_modules; |
| 172 | + |
| 173 | + for (Size tp_rank = 0; tp_rank < tp_size; ++tp_rank) { |
| 174 | + auto module = std::make_unique<MockLinearModule>(64, 32, device, tp_dim, tp_rank, tp_size); |
| 175 | + tp_modules.push_back(std::move(module)); |
| 176 | + } |
| 177 | + |
| 178 | + // Verify each partition has correct shape |
| 179 | + for (size_t i = 0; i < tp_modules.size(); ++i) { |
| 180 | + const auto &weight = tp_modules[i]->get_weight(); |
| 181 | + const auto &bias = tp_modules[i]->get_bias(); |
| 182 | + |
| 183 | + // Weight should be partitioned along output dimension (dim 0) |
| 184 | + if (weight->shape() != std::vector<size_t>({8, 64})) { // 32/4 = 8 |
| 185 | + spdlog::error("TP rank {}: Weight shape mismatch. Expected [8, 64], got [{}]", |
| 186 | + i, formatShape(weight->shape())); |
| 187 | + return false; |
| 188 | + } |
| 189 | + |
| 190 | + // Bias should be partitioned along output dimension |
| 191 | + if (bias->shape() != std::vector<size_t>({8})) { // 32/4 = 8 |
| 192 | + spdlog::error("TP rank {}: Bias shape mismatch. Expected [8], got [{}]", |
| 193 | + i, formatShape(bias->shape())); |
| 194 | + return false; |
| 195 | + } |
| 196 | + |
| 197 | + spdlog::debug("TP rank {}: weight shape [{}], bias shape [{}]", |
| 198 | + i, formatShape(weight->shape()), formatShape(bias->shape())); |
| 199 | + |
| 200 | + tp_modules[i]->load_parameter_from_blob("weight", w_data.data()); |
| 201 | + tp_modules[i]->load_parameter_from_blob("bias", b_data.data()); |
| 202 | + |
| 203 | + auto weight_loaded = infinicore::Tensor::from_blob( |
| 204 | + w_data.data(), |
| 205 | + {32, 64}, |
| 206 | + infinicore::DataType::F32, |
| 207 | + infinicore::Device::cpu()) |
| 208 | + ->narrow({{0, i * 8, 8}}) |
| 209 | + ->to(device); // Narrow to get the partition |
| 210 | + auto bias_loaded = infinicore::Tensor::from_blob( |
| 211 | + b_data.data(), |
| 212 | + {32}, |
| 213 | + infinicore::DataType::F32, |
| 214 | + infinicore::Device::cpu()) |
| 215 | + ->narrow({{0, i * 8, 8}}) |
| 216 | + ->to(device); // Narrow to get the partition |
| 217 | + |
| 218 | + if (!tensorsAllClose(tp_modules[i]->get_weight(), weight_loaded, 1e-6, 1e-6)) { |
| 219 | + spdlog::error("TP rank {}: Weight values do not match after load_parameter_from_blob", i); |
| 220 | + return false; |
| 221 | + } |
| 222 | + |
| 223 | + if (!tensorsAllClose(tp_modules[i]->get_bias(), bias_loaded, 1e-6, 1e-6)) { |
| 224 | + spdlog::error("TP rank {}: Bias values do not match after load_parameter_from_blob", i); |
| 225 | + return false; |
| 226 | + } |
| 227 | + } |
| 228 | + } |
| 229 | + |
| 230 | + { |
| 231 | + spdlog::info("Test tp_size=4 tp_dim=1"); |
| 232 | + Size tp_size = 4; |
| 233 | + Size tp_dim = 1; |
| 234 | + std::vector<std::unique_ptr<MockLinearModule>> tp_modules; |
| 235 | + |
| 236 | + for (Size tp_rank = 0; tp_rank < tp_size; ++tp_rank) { |
| 237 | + auto module = std::make_unique<MockLinearModule>(64, 32, device, tp_dim, tp_rank, tp_size); |
| 238 | + tp_modules.push_back(std::move(module)); |
| 239 | + } |
| 240 | + |
| 241 | + // Verify each partition has correct shape |
| 242 | + for (size_t i = 0; i < tp_modules.size(); ++i) { |
| 243 | + const auto &weight = tp_modules[i]->get_weight(); |
| 244 | + const auto &bias = tp_modules[i]->get_bias(); |
| 245 | + |
| 246 | + // Weight should be partitioned along output dimension (dim 0) |
| 247 | + if (weight->shape() != std::vector<size_t>({32, 16})) { // 64/4 = 16 |
| 248 | + spdlog::error("TP rank {}: Weight shape mismatch. Expected [32, 16], got [{}]", |
| 249 | + i, formatShape(weight->shape())); |
| 250 | + return false; |
| 251 | + } |
| 252 | + |
| 253 | + // Bias should be partitioned along output dimension |
| 254 | + if (bias->shape() != std::vector<size_t>({32})) { // Bias not partitioned when tp_dim=1 |
| 255 | + spdlog::error("TP rank {}: Bias shape mismatch. Expected [32], got [{}]", |
| 256 | + i, formatShape(bias->shape())); |
| 257 | + return false; |
| 258 | + } |
| 259 | + |
| 260 | + spdlog::debug("TP rank {}: weight shape [{}], bias shape [{}]", |
| 261 | + i, formatShape(weight->shape()), formatShape(bias->shape())); |
| 262 | + ; |
| 263 | + tp_modules[i]->load_parameter_from_blob("weight", w_data.data()); |
| 264 | + tp_modules[i]->load_parameter_from_blob("bias", b_data.data()); |
| 265 | + |
| 266 | + auto weight_loaded = infinicore::Tensor::from_blob( |
| 267 | + w_data.data(), |
| 268 | + {32, 64}, |
| 269 | + infinicore::DataType::F32, |
| 270 | + infinicore::Device::cpu()) |
| 271 | + ->narrow({{1, i * 16, 16}}) |
| 272 | + ->to(device); // Narrow to get the partition |
| 273 | + auto bias_loaded = infinicore::Tensor::from_blob( |
| 274 | + b_data.data(), |
| 275 | + {32}, |
| 276 | + infinicore::DataType::F32, |
| 277 | + infinicore::Device::cpu()) |
| 278 | + ->to(device); // Narrow to get the partition |
| 279 | + if (!tensorsAllClose(tp_modules[i]->get_weight(), weight_loaded, 1e-6, 1e-6)) { |
| 280 | + spdlog::error("TP rank {}: Weight values do not match after load_parameter_from_blob", i); |
| 281 | + return false; |
| 282 | + } |
| 283 | + if (!tensorsAllClose(tp_modules[i]->get_bias(), bias_loaded, 1e-6, 1e-6)) { |
| 284 | + spdlog::error("TP rank {}: Bias values do not match after load_parameter_from_blob", i); |
| 285 | + return false; |
| 286 | + } |
| 287 | + } |
| 288 | + } |
| 289 | + |
| 290 | + spdlog::info("=== All Tensor Parallel Parameter Tests Passed ==="); |
| 291 | + return true; |
| 292 | + |
| 293 | + } catch (const std::exception &e) { |
| 294 | + spdlog::error("Exception in testTensorParallelParameters: {}", e.what()); |
| 295 | + return false; |
| 296 | + } |
| 297 | + }); |
| 298 | +} |
| 299 | + |
118 | 300 | // Test 2: Advanced load state dict functionality (hierarchical modules) |
119 | 301 | TestResult NNModuleTest::testLoadStateDict() { |
120 | 302 | return measureTime("AdvancedLoadStateDict", [this]() { |
@@ -384,6 +566,8 @@ TestResult NNModuleTest::testParameterLoading() { |
384 | 566 | return false; |
385 | 567 | } |
386 | 568 |
|
| 569 | + MockLinearModule module_row_parallel(3, 2, infinicore::Device(), 0, 1, 2); |
| 570 | + |
387 | 571 | spdlog::info("Parameter loading test passed"); |
388 | 572 | return true; |
389 | 573 | } catch (const std::exception &e) { |
@@ -1708,16 +1892,17 @@ TestResult NNModuleTest::run() { |
1708 | 1892 | << "InfiniCore nn::Module Test Suite\n" |
1709 | 1893 | << "==============================================" << std::endl; |
1710 | 1894 |
|
1711 | | - results.push_back(testBasicModuleCreation()); // Merged: creation + parameters + state_dict + load |
1712 | | - results.push_back(testLoadStateDict()); // Advanced: hierarchical modules |
1713 | | - results.push_back(testModuleHierarchy()); // Demonstrates hierarchical construction |
1714 | | - results.push_back(testParameterLoading()); // Blob loading |
1715 | | - results.push_back(testModuleLinear()); // Linear module comprehensive test |
1716 | | - results.push_back(testModuleEmbedding()); // Embedding module test |
1717 | | - results.push_back(testModuleRMSNorm()); // RMSNorm module test |
1718 | | - results.push_back(testModuleRoPE()); // RoPE module test |
1719 | | - results.push_back(testDtypeAssertion()); // Dtype assertion test |
1720 | | - results.push_back(testTinyLlamaConstruction()); // Comprehensive: TinyLlama model test |
| 1895 | + results.push_back(testBasicModuleCreation()); // Merged: creation + parameters + state_dict + load |
| 1896 | + results.push_back(testTensorParallelParameters()); // Tensor-parallel parameters |
| 1897 | + results.push_back(testLoadStateDict()); // Advanced: hierarchical modules |
| 1898 | + results.push_back(testModuleHierarchy()); // Demonstrates hierarchical construction |
| 1899 | + results.push_back(testParameterLoading()); // Blob loading |
| 1900 | + results.push_back(testModuleLinear()); // Linear module comprehensive test |
| 1901 | + results.push_back(testModuleEmbedding()); // Embedding module test |
| 1902 | + results.push_back(testModuleRMSNorm()); // RMSNorm module test |
| 1903 | + results.push_back(testModuleRoPE()); // RoPE module test |
| 1904 | + results.push_back(testDtypeAssertion()); // Dtype assertion test |
| 1905 | + results.push_back(testTinyLlamaConstruction()); // Comprehensive: TinyLlama model test |
1721 | 1906 |
|
1722 | 1907 | // Check if all tests passed |
1723 | 1908 | bool all_passed = true; |
|
0 commit comments