Skip to content

Commit f410c47

Browse files
pmbrown1055Ryan Lai
authored andcommitted
Feature/garbage data range (#280)
* Argument for tensor garbage data with a range of values. * Add GarbageDataMaxValue to limit generated garbage data to values between 0 and the specified maximum.
1 parent b589f4e commit f410c47

File tree

5 files changed

+66
-70
lines changed

5 files changed

+66
-70
lines changed

Tools/WinMLRunner/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ Required command-Line arguments:
5959
-DebugEvaluate: Print evaluation debug output to debug console if debugger is present.
6060
-Terse: Terse Mode (suppresses repetitive console output)
6161
-AutoScale <interpolationMode>: Enable image autoscaling and set the interpolation mode [Nearest, Linear, Cubic, Fant]
62+
-GarbageDataMaxValue <maxValue>: Limit generated garbage data to a maximum value. Helpful if input data is used as an index.
6263
6364
Concurrency Options:
6465
-ConcurrentLoad: load models concurrently

Tools/WinMLRunner/src/BindingUtilities.h

Lines changed: 54 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -129,60 +129,23 @@ template <> struct TensorKindToValue<TensorKind::String>
129129
typedef TensorString Type;
130130
};
131131

132-
template <TensorKind T, typename ToType, typename FromType>
133-
ToType ConvertToPointerType(FromType value)
132+
template <TensorKind T, typename ToType, typename FromType> ToType ConvertToPointerType(FromType value)
134133
{
135134
static_assert(true, "No TensorKind mapped for given type!");
136135
return 0;
137136
};
138-
template <> uint8_t ConvertToPointerType<TensorKind::UInt8>(float value)
139-
{
140-
return static_cast<uint8_t>(value);
141-
};
142-
template <> int8_t ConvertToPointerType<TensorKind::Int8>(float value)
143-
{
144-
return static_cast<int8_t>(value);
145-
};
146-
template <> uint16_t ConvertToPointerType<TensorKind::UInt16>(float value)
147-
{
148-
return static_cast<uint16_t>(value);
149-
};
150-
template <> int16_t ConvertToPointerType<TensorKind::Int16>(float value)
151-
{
152-
return static_cast<int16_t>(value);
153-
};
154-
template <> uint32_t ConvertToPointerType<TensorKind::UInt32>(float value)
155-
{
156-
return static_cast<uint32_t>(value);
157-
};
158-
template <> int32_t ConvertToPointerType<TensorKind::Int32>(float value)
159-
{
160-
return static_cast<int32_t>(value);
161-
};
162-
template <> uint64_t ConvertToPointerType<TensorKind::UInt64>(float value)
163-
{
164-
return static_cast<uint64_t>(value);
165-
};
166-
template <> int64_t ConvertToPointerType<TensorKind::Int64>(float value)
167-
{
168-
return static_cast<int64_t>(value);
169-
};
170-
template <> boolean ConvertToPointerType<TensorKind::Boolean>(float value)
171-
{
172-
return static_cast<boolean>(value);
173-
};
174-
template <> double ConvertToPointerType<TensorKind::Double>(double value)
175-
{
176-
return static_cast<double>(value);
177-
};
178-
template <> float ConvertToPointerType<TensorKind::Float>(float value)
179-
{
180-
return static_cast<float>(value);
181-
};
182-
template <> HALF ConvertToPointerType<TensorKind::Float16>(float value)
183-
{
184-
return XMConvertFloatToHalf(value);
185-
};
137+
template <> uint8_t ConvertToPointerType<TensorKind::UInt8>(float value) { return static_cast<uint8_t>(value); };
138+
template <> int8_t ConvertToPointerType<TensorKind::Int8>(float value) { return static_cast<int8_t>(value); };
139+
template <> uint16_t ConvertToPointerType<TensorKind::UInt16>(float value) { return static_cast<uint16_t>(value); };
140+
template <> int16_t ConvertToPointerType<TensorKind::Int16>(float value) { return static_cast<int16_t>(value); };
141+
template <> uint32_t ConvertToPointerType<TensorKind::UInt32>(float value) { return static_cast<uint32_t>(value); };
142+
template <> int32_t ConvertToPointerType<TensorKind::Int32>(float value) { return static_cast<int32_t>(value); };
143+
template <> uint64_t ConvertToPointerType<TensorKind::UInt64>(float value) { return static_cast<uint64_t>(value); };
144+
template <> int64_t ConvertToPointerType<TensorKind::Int64>(float value) { return static_cast<int64_t>(value); };
145+
template <> boolean ConvertToPointerType<TensorKind::Boolean>(float value) { return static_cast<boolean>(value); };
146+
template <> double ConvertToPointerType<TensorKind::Double>(double value) { return static_cast<double>(value); };
147+
template <> float ConvertToPointerType<TensorKind::Float>(float value) { return static_cast<float>(value); };
148+
template <> HALF ConvertToPointerType<TensorKind::Float16>(float value) { return XMConvertFloatToHalf(value); };
186149
template <> winrt::hstring ConvertToPointerType<TensorKind::String>(winrt::hstring value)
187150
{
188151
return static_cast<winrt::hstring>(value);
@@ -219,7 +182,7 @@ void GetHeightAndWidthFromLearningModelFeatureDescriptor(const ILearningModelFea
219182
namespace BindingUtilities
220183
{
221184
static unsigned int seed = 0;
222-
static std::independent_bits_engine<std::default_random_engine, CHAR_BIT, unsigned int> randomBitsEngine;
185+
static std::independent_bits_engine<std::default_random_engine, CHAR_BIT, unsigned int> randomBitsEngineChar;
223186

224187
SoftwareBitmap GenerateGarbageImage(const ILearningModelFeatureDescriptor& modelFeatureDescriptor,
225188
InputDataType inputDataType)
@@ -234,8 +197,8 @@ namespace BindingUtilities
234197

235198
// Generate values for the image based on a seed
236199
std::vector<uint8_t> data(totalByteSize);
237-
randomBitsEngine.seed(seed++);
238-
std::generate(data.begin(), data.end(), randomBitsEngine);
200+
randomBitsEngineChar.seed(seed++);
201+
std::generate(data.begin(), data.end(), randomBitsEngineChar);
239202

240203
// Write the values to a buffer
241204
winrt::array_view<const uint8_t> dataView(data);
@@ -367,18 +330,18 @@ namespace BindingUtilities
367330
}
368331

369332
// Check to see if csv didn't fill in entire buffer and throw or fill with zeros?
370-
if (pos != (inputBufferDesc.totalSizeInBytes * inputBufferDesc.numChannelsPerElement) / inputBufferDesc.elementStrideInBytes)
333+
if (pos != (inputBufferDesc.totalSizeInBytes * inputBufferDesc.numChannelsPerElement) /
334+
inputBufferDesc.elementStrideInBytes)
371335
{
372336
throw hresult_invalid_argument(L"CSV input size/shape is different from what model expects!");
373337
}
374-
375338
}
376339

377340
// Roll the array correctly for the tensor
378341
template <TensorKind TKind, typename InputType>
379342
void CopyTensorFromBuffer(void* actualData, uint32_t tensorHeight, uint32_t tensorWidth,
380-
const InputBufferDesc& inputBufferDesc, float scale,
381-
const std::vector<float>& means, const std::vector<float>& stddevs)
343+
const InputBufferDesc& inputBufferDesc, float scale, const std::vector<float>& means,
344+
const std::vector<float>& stddevs)
382345
{
383346
using WriteType = typename TensorKindToPointerType<TKind>::Type;
384347

@@ -390,20 +353,35 @@ namespace BindingUtilities
390353
{
391354
for (uint32_t channel = 0; channel < inputBufferDesc.numChannelsPerElement; ++channel)
392355
{
393-
pDataOut[element * elementOffsetMultiplier + channel * channelOffsetMultiplier] =
394-
ConvertToPointerType<TKind, WriteType>(
395-
((pDataIn[channel] / scale) - means[channel]) / stddevs[channel]);
356+
pDataOut[element * elementOffsetMultiplier + channel * channelOffsetMultiplier] =
357+
ConvertToPointerType<TKind, WriteType>(((pDataIn[channel] / scale) - means[channel]) /
358+
stddevs[channel]);
396359
}
397360
pDataIn += inputBufferDesc.elementStrideInBytes / sizeof(InputType);
398361
}
399362
}
400363

401-
template <TensorKind T>
364+
template <TensorKind TKind, typename WriteType>
365+
static void GenerateRandomData(WriteType* data, uint32_t sizeInBytes, uint32_t maxValue)
366+
{
367+
static std::independent_bits_engine<std::default_random_engine, sizeof(uint32_t) * 8, uint32_t> randomBitsEngine;
368+
randomBitsEngine.seed(seed++);
369+
370+
WriteType* begin = data;
371+
WriteType* end = reinterpret_cast<WriteType*>(reinterpret_cast<BYTE*>(data) + sizeInBytes);
372+
while (begin <= end)
373+
{
374+
*begin = maxValue * static_cast<float>(randomBitsEngine()) / (randomBitsEngine.max)();
375+
++begin;
376+
}
377+
}
378+
379+
template <TensorKind TKind>
402380
static ITensor CreateTensor(const CommandLineArgs& args, const std::vector<int64_t>& tensorShape,
403381
const InputBindingType inputBindingType, const InputBufferDesc& inputBufferDesc)
404382
{
405-
using TensorValue = typename TensorKindToValue<T>::Type;
406-
using WriteType = typename TensorKindToPointerType<T>::Type;
383+
using TensorValue = typename TensorKindToValue<TKind>::Type;
384+
using WriteType = typename TensorKindToPointerType<TKind>::Type;
407385

408386
// Map the incoming Tensor as a TensorNative to get the actual data buffer.
409387
auto tensorValue = TensorValue::Create(tensorShape);
@@ -471,27 +449,33 @@ namespace BindingUtilities
471449
break;
472450

473451
default:
474-
throw hresult_invalid_argument(L"CreateTensor<T>: Unhandled SoftwareBitmap pixel format");
452+
throw hresult_invalid_argument(
453+
L"CreateTensor<TKind>: Unhandled SoftwareBitmap pixel format");
475454
}
476455
break;
477456
default:
478-
throw hresult_invalid_argument(L"CreateTensor<T>: Unknown Tensorize Function");
457+
throw hresult_invalid_argument(L"CreateTensor<TKind>: Unknown Tensorize Function");
479458
}
480459

481460
switch (inputBufferDesc.channelFormat)
482461
{
483462
case TensorKind::UInt8:
484-
CopyTensorFromBuffer<T, uint8_t>(actualData, tensorHeight, tensorWidth, inputBufferDesc, scale,
485-
means, stddevs);
463+
CopyTensorFromBuffer<TKind, uint8_t>(actualData, tensorHeight, tensorWidth, inputBufferDesc, scale,
464+
means, stddevs);
486465
break;
487466
case TensorKind::Float:
488-
CopyTensorFromBuffer<T, float>(actualData, tensorHeight, tensorWidth, inputBufferDesc, scale,
489-
means, stddevs);
467+
CopyTensorFromBuffer<TKind, float>(actualData, tensorHeight, tensorWidth, inputBufferDesc, scale,
468+
means, stddevs);
490469
break;
491470
default:
492471
throw hresult_not_implemented(L"Creating Tensors for Input Images with unhandled channel format!");
493472
}
494473
}
474+
// Garbage Data
475+
else if (args.IsGarbageDataRange())
476+
{
477+
GenerateRandomData<TKind>(actualData, actualSizeInBytes, args.GarbageDataMaxValue());
478+
}
495479

496480
if (inputBindingType == InputBindingType::CPU)
497481
{
@@ -653,7 +637,7 @@ namespace BindingUtilities
653637
} // namespace BindingUtilities
654638

655639
// Binds tensor floats, ints, doubles from CSV data.
656-
ITensor CreateBindableTensor(const ILearningModelFeatureDescriptor& description, const std::wstring &imagePath,
640+
ITensor CreateBindableTensor(const ILearningModelFeatureDescriptor& description, const std::wstring& imagePath,
657641
const InputBindingType inputBindingType, const InputDataType inputDataType,
658642
const CommandLineArgs& args, uint32_t iterationNum)
659643
{

Tools/WinMLRunner/src/CommandLineArgs.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ void CommandLineArgs::PrintUsage()
4949
std::cout << " -InputImageFolder <path to directory of images> : specify folder of images to bind to model"
5050
<< std::endl;
5151
std::cout << " -TopK <number> : print top <number> values in the result. Default to 1" << std::endl;
52+
std::cout << " -GarbageDataMaxValue <number> : limit garbage data range to a max random value" << std::endl;
5253
std::cout << " -BaseOutputPath [<fully qualified path>] : base output directory path for results, default to cwd"
5354
<< std::endl;
5455
std::cout << " -PerfOutput [<path>] : fully qualified or relative path including csv filename for perf results"
@@ -363,6 +364,11 @@ CommandLineArgs::CommandLineArgs(const std::vector<std::wstring>& args)
363364
CheckNextArgument(args, i);
364365
SetTopK(std::stoi(args[++i].c_str()));
365366
}
367+
else if ((_wcsicmp(args[i].c_str(), L"-GarbageDataMaxValue") == 0))
368+
{
369+
CheckNextArgument(args, i);
370+
SetGarbageDataMaxValue(std::stoul(args[++i].c_str()));
371+
}
366372
else
367373
{
368374
std::wstring msg = L"Unknown option ";

Tools/WinMLRunner/src/CommandLineArgs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ class CommandLineArgs
104104
uint32_t NumThreads() const { return m_numThreads; }
105105
uint32_t ThreadInterval() const { return m_threadInterval; } // Thread interval in milliseconds
106106
uint32_t TopK() const { return m_topK; }
107+
uint32_t GarbageDataMaxValue() const { return m_garbageDataMaxValue; }
108+
bool IsGarbageDataRange() const { return m_garbageDataMaxValue != 0; }
107109

108110
void ToggleCPU(bool useCPU) { m_useCPU = useCPU; }
109111
void ToggleGPU(bool useGPU) { m_useGPU = useGPU; }
@@ -138,6 +140,7 @@ class CommandLineArgs
138140
void SetSessionCreationIterations(const uint32_t iterations) { m_numSessionIterations = iterations; }
139141
void SetLoadIterations(const uint32_t iterations) { m_numLoadIterations = iterations; }
140142
void AddPerformanceFileMetadata(const std::string& key, const std::string& value);
143+
void SetGarbageDataMaxValue(const uint32_t value) { m_garbageDataMaxValue = value; }
141144

142145
// Stop iterating when total time of iterations after the first iteration exceeds time limit.
143146
void SetIterationTimeLimit(const double milliseconds)
@@ -197,6 +200,7 @@ class CommandLineArgs
197200
uint32_t m_numThreads = 1;
198201
uint32_t m_threadInterval = 0;
199202
uint32_t m_topK = 1;
203+
uint32_t m_garbageDataMaxValue = 0;
200204
std::vector<std::pair<std::string, std::string>> m_perfFileMetadata;
201205

202206
void CheckNextArgument(const std::vector<std::wstring>& args, UINT argIdx, UINT checkIdx = 0);

Tools/WinMLRunner/src/Common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <winrt/Windows.Media.h>
1212
#include <winrt/Windows.Storage.h>
1313
#include <winrt/Windows.Storage.Streams.h>
14+
#include <array>
1415
#include <vector>
1516
#include <string>
1617
#include <iostream>

0 commit comments

Comments
 (0)