-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcpp_fallback_path.hpp
More file actions
156 lines (137 loc) · 6.23 KB
/
Copy pathcpp_fallback_path.hpp
File metadata and controls
156 lines (137 loc) · 6.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*!
\file cpp_fallback_path.hpp
\author Sho Ikeda
\brief C++ fallback inference path for texture MLP inference example
\copyright Copyright (c) 2026 Advanced Micro Devices, Inc. All Rights Reserved.
SPDX-License-Identifier: MIT
This header is included from example.cpp inside the anonymous namespace.
It depends on types and functions defined earlier in example.cpp:
- MlpConfig<Type>, mapToLdr<Type>
and on headers already included by example.cpp:
- common/cpp_fallback.hpp, kernel/texture_inference_common.hlsl
*/
#ifndef MINIDXNN_EXAMPLE_01_CPP_FALLBACK_PATH_HPP
#define MINIDXNN_EXAMPLE_01_CPP_FALLBACK_PATH_HPP 1
// Templated forward kernel: delegates to texkernel::inferenceStep from shared HLSL.
template <ex::Arithmetic Type, uint NUM_LAYERS, int HIDDEN_DIM,
typename ActivationHiddenT, typename ActivationLastT>
auto cppFallbackForwardKernel(const ex::PackedMlpBuffers<Type>& packed,
const std::vector<Type>& uvData,
std::vector<Type>& output,
size_t numTasks) -> void
{
ByteAddressBuffer uvBuf{uvData};
RWByteAddressBuffer outBuf{output};
const uint totalTasks = static_cast<uint>(numTasks);
const uint numThreads = std::max(1u, std::thread::hardware_concurrency());
const uint tasksPerThread = totalTasks / numThreads;
const uint remainder = totalTasks % numThreads;
std::vector<std::thread> threads;
threads.reserve(numThreads);
uint taskStart = 0;
for (uint t = 0; t < numThreads; ++t) {
const uint taskEnd = taskStart + tasksPerThread + (t < remainder ? 1 : 0);
threads.emplace_back([&, taskStart, taskEnd]() {
for (uint task = taskStart; task < taskEnd; ++task) {
texkernel::inferenceStep<Type, NUM_LAYERS, HIDDEN_DIM,
mininn::impl::TypeTraits<Type>::COMPONENT_TYPE,
dx::linalg::MATRIX_LAYOUT_ROW_MAJOR,
ActivationHiddenT, ActivationLastT,
128, 16, 64, true>(
task, uvBuf, outBuf, packed.weightBAB(), packed.biasBAB(),
packed.matrixSizes, totalTasks);
}
});
taskStart = taskEnd;
}
for (auto& th : threads) {
th.join();
}
}
// Dispatch hidden-layer activation type at runtime.
template <ex::Arithmetic Type, uint NUM_LAYERS, int HIDDEN_DIM>
auto dispatchActivation(ex::ActivationType hiddenAct,
const ex::PackedMlpBuffers<Type>& packed,
const std::vector<Type>& uvData,
std::vector<Type>& output,
size_t numTasks) -> bool
{
// Last activation is always Sigmoid for this example.
using Sigmoid = mininn::SigmoidActivation;
switch (hiddenAct) {
case ex::ActivationType::RELU:
cppFallbackForwardKernel<Type, NUM_LAYERS, HIDDEN_DIM, mininn::ReluActivation, Sigmoid>(packed, uvData, output, numTasks);
return true;
case ex::ActivationType::IDENTITY:
cppFallbackForwardKernel<Type, NUM_LAYERS, HIDDEN_DIM, mininn::IdentityActivation, Sigmoid>(packed, uvData, output, numTasks);
return true;
case ex::ActivationType::SIGMOID:
cppFallbackForwardKernel<Type, NUM_LAYERS, HIDDEN_DIM, mininn::SigmoidActivation, Sigmoid>(packed, uvData, output, numTasks);
return true;
case ex::ActivationType::LEAKY_RELU:
cppFallbackForwardKernel<Type, NUM_LAYERS, HIDDEN_DIM, mininn::LeakyReluActivation, Sigmoid>(packed, uvData, output, numTasks);
return true;
case ex::ActivationType::TANH:
default:
return false;
}
}
// Dispatch NUM_LAYERS and HIDDEN_DIM at runtime.
// Supports common MLP configurations used in texture inference.
template <ex::Arithmetic Type>
auto dispatchForward(size_t numLayers, size_t hiddenDim,
ex::ActivationType hiddenAct,
const ex::PackedMlpBuffers<Type>& packed,
const std::vector<Type>& uvData,
std::vector<Type>& output,
size_t numTasks) -> bool
{
// Macro to reduce boilerplate for each (NUM_LAYERS, HIDDEN_DIM) pair
#define DISPATCH_CASE(NL, HD) \
if (numLayers == (NL) && hiddenDim == (HD)) \
return dispatchActivation<Type, (NL), (HD)>(hiddenAct, packed, uvData, output, numTasks);
// 2 layers (1 backbone): common small models
DISPATCH_CASE(2, 8) DISPATCH_CASE(2, 16)
DISPATCH_CASE(2, 32) DISPATCH_CASE(2, 64)
// 3 layers (2 backbone)
DISPATCH_CASE(3, 8) DISPATCH_CASE(3, 16)
DISPATCH_CASE(3, 32) DISPATCH_CASE(3, 64)
// 4 layers (3 backbone)
DISPATCH_CASE(4, 16) DISPATCH_CASE(4, 32)
DISPATCH_CASE(4, 64)
// 5 layers (4 backbone)
DISPATCH_CASE(5, 16) DISPATCH_CASE(5, 32)
DISPATCH_CASE(5, 64)
#undef DISPATCH_CASE
return false;
}
/*!
\brief Run inference using the C++ fallback path (mlp.hlsl compiled as C++).
Creates ByteAddressBuffers from packed MLP layer data and calls mininn::forward.
*/
template <ex::Arithmetic Type>
auto runCppFallbackInference(const MlpConfig<Type>& mlpConfig,
const std::vector<Type>& uvData,
ex::PixmapU8& texture) -> void
{
const std::span mlpData = std::span{mlpConfig.m_layers};
const bool hasBias = mlpConfig.m_hasBias;
const size_t numTasks = texture.width() * texture.height();
const size_t numLayers = mlpData.size();
const size_t hiddenDim = mlpData.front().outputDimension();
const ex::ActivationType hiddenAct = mlpData.front().configuration().m_activation;
ex::PackedMlpBuffers<Type> packed;
packed.pack(mlpData, hasBias);
std::vector<Type> output(numTasks * 2);
const std::chrono::high_resolution_clock::time_point startTime = std::chrono::high_resolution_clock::now();
if (!dispatchForward<Type>(numLayers, hiddenDim, hiddenAct, packed, uvData, output, numTasks)) {
std::cerr << std::format("[Error] C++ fallback: unsupported MLP config (layers={}, hiddenDim={})\n",
numLayers, hiddenDim);
std::abort();
}
const std::chrono::high_resolution_clock::time_point endTime = std::chrono::high_resolution_clock::now();
const double elapsedMs = std::chrono::duration<double, std::milli>(endTime - startTime).count();
std::cout << std::format("Reconstruction time: {:.3f} ms\n", elapsedMs);
ex::mapToLdr<Type>(output, texture);
}
#endif /* MINIDXNN_EXAMPLE_01_CPP_FALLBACK_PATH_HPP */