2016-06-10 07:54:26 +03:00
|
|
|
//
|
|
|
|
// Copyright (c) Microsoft. All rights reserved.
|
|
|
|
// Licensed under the MIT license. See LICENSE.md file in the project root for full license information.
|
|
|
|
//
|
|
|
|
#pragma once
|
2016-07-27 03:01:25 +03:00
|
|
|
#include "Basics.h"
|
2016-06-10 07:54:26 +03:00
|
|
|
|
|
|
|
namespace Microsoft { namespace MSR { namespace CNTK {
|
|
|
|
|
2016-06-27 19:23:56 +03:00
|
|
|
// RawType - input type to the quantizer. Currently CNTK supports float or double as RawType.
|
2016-06-10 07:54:26 +03:00
|
|
|
// QuantizedType - output type of the quantizer
|
|
|
|
template <class RawType, class QuantizedType>
|
2016-06-27 19:23:56 +03:00
|
|
|
class QuantizerBase
|
2016-06-10 07:54:26 +03:00
|
|
|
{
|
|
|
|
public:
|
2016-07-27 03:01:25 +03:00
|
|
|
QuantizerBase()
|
|
|
|
{
|
|
|
|
rangeMax = std::numeric_limits<QuantizedType>::max();
|
|
|
|
}
|
|
|
|
virtual void Quantize(const ArrayRef<RawType>& input, ArrayRef<QuantizedType>& output) = 0;
|
|
|
|
virtual void Dequantize(const ArrayRef<QuantizedType>& input, ArrayRef<RawType>& output) = 0;
|
2016-06-10 07:54:26 +03:00
|
|
|
|
|
|
|
protected:
|
2016-07-27 03:01:25 +03:00
|
|
|
QuantizedType rangeMax;
|
2016-06-10 07:54:26 +03:00
|
|
|
};
|
|
|
|
|
2016-06-27 19:23:56 +03:00
|
|
|
// Symmetric quantizer.
|
|
|
|
// Quantization is achieved by
|
|
|
|
// 1. Finding the absolute max of values to be quantized.
|
2016-07-27 03:01:25 +03:00
|
|
|
// 2. Adjusting the absolute max with extraBits parameter.
|
2016-06-27 19:23:56 +03:00
|
|
|
// 3. Scaling all values in the collection to be within the symmetric range of the QuantizedType
|
2016-06-10 07:54:26 +03:00
|
|
|
template <class RawType, class QuantizedType>
|
2016-06-27 19:23:56 +03:00
|
|
|
class SymmetricQuantizer : public QuantizerBase<RawType, QuantizedType>
|
2016-06-10 07:54:26 +03:00
|
|
|
{
|
2016-07-27 03:01:25 +03:00
|
|
|
RawType m_quantizeFactor;
|
|
|
|
RawType m_inverseQuantizerFactor;
|
2016-06-16 06:36:45 +03:00
|
|
|
RawType m_absMax;
|
2016-06-10 07:54:26 +03:00
|
|
|
public:
|
|
|
|
// elements - collection to be quantized
|
|
|
|
// extraBits decreases the quantization normalizer to prevent integer overflow during BLAS routines.
|
2016-06-27 19:23:56 +03:00
|
|
|
// Higher extraBits will decrease precision of quantization, but will make BLAS routines less prone to overflow.
|
|
|
|
// For quantization with shorts, recommended value of extraBits is 1-3.
|
|
|
|
// This constructor accepts the collection of RawType to initialize internal quantizer
|
|
|
|
// and then apply this quantizer to collections with similar range as the one it was initialized with.
|
2016-07-27 03:01:25 +03:00
|
|
|
SymmetricQuantizer(const ArrayRef<RawType>& input, size_t extraBits)
|
2016-06-10 07:54:26 +03:00
|
|
|
{
|
2016-07-27 03:01:25 +03:00
|
|
|
m_absMax = FindAbsMax(input);
|
|
|
|
Initialize(m_absMax, extraBits);
|
2016-06-10 07:54:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// absoluteMax - the range of the quantizer (normally represents maximum absolute value of the values in the collection to be quantized).
|
|
|
|
// extraBits - see comment in another ctor
|
|
|
|
SymmetricQuantizer(RawType absoluteMax, size_t extraBits)
|
|
|
|
{
|
2016-07-27 03:01:25 +03:00
|
|
|
Initialize(absoluteMax, extraBits);
|
2016-06-10 07:54:26 +03:00
|
|
|
}
|
|
|
|
|
2016-06-27 19:23:56 +03:00
|
|
|
// Perform quantization of the input collection, put result into pre-allocated output collection
|
2016-07-27 03:01:25 +03:00
|
|
|
virtual void Quantize(const ArrayRef<RawType>& input, ArrayRef<QuantizedType>& output)
|
2016-06-10 07:54:26 +03:00
|
|
|
{
|
2016-07-27 03:01:25 +03:00
|
|
|
assert(input.size() == output.size());
|
|
|
|
|
|
|
|
for (size_t i = 0; i < input.size(); i++)
|
2016-06-10 07:54:26 +03:00
|
|
|
{
|
2016-06-16 06:36:45 +03:00
|
|
|
#ifdef _DEBUG
|
|
|
|
assert(abs(input[i]) <= m_absMax);
|
|
|
|
#endif
|
2016-07-27 03:01:25 +03:00
|
|
|
output[i] = (QuantizedType) round((input[i] * m_quantizeFactor));
|
2016-06-10 07:54:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-06-27 19:23:56 +03:00
|
|
|
// Accept quantized collection as input, put de-quantization result into pre-allocated output collection.
|
2016-07-27 03:01:25 +03:00
|
|
|
virtual void Dequantize(const ArrayRef<QuantizedType>& input, ArrayRef<RawType>& output)
|
2016-06-10 07:54:26 +03:00
|
|
|
{
|
2016-07-27 03:01:25 +03:00
|
|
|
assert(input.size() == output.size());
|
|
|
|
|
|
|
|
for (size_t i = 0; i < input.size(); i++)
|
2016-06-10 07:54:26 +03:00
|
|
|
{
|
2016-07-27 03:01:25 +03:00
|
|
|
output[i] = (RawType)(input[i] * m_inverseQuantizerFactor);
|
2016-06-10 07:54:26 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Find absolute maximum value
|
2016-07-27 03:01:25 +03:00
|
|
|
RawType FindAbsMax(const ArrayRef<RawType>& arrayRef)
|
2016-06-10 07:54:26 +03:00
|
|
|
{
|
2016-07-27 03:01:25 +03:00
|
|
|
RawType maxElem = *std::max_element(arrayRef.begin(), arrayRef.end());
|
|
|
|
RawType minElem = *std::min_element(arrayRef.begin(), arrayRef.end());
|
2016-06-10 07:54:26 +03:00
|
|
|
|
|
|
|
return std::max(maxElem, std::abs(minElem));
|
|
|
|
}
|
2016-07-27 03:01:25 +03:00
|
|
|
|
|
|
|
void Initialize(RawType absoluteMax, size_t extraBits)
|
|
|
|
{
|
|
|
|
RawType shiftedMax = absoluteMax * (1 << extraBits);
|
|
|
|
if (shiftedMax == 0)
|
|
|
|
{
|
|
|
|
LogicError("The absolute max element in the sequence to be quantized is 0.");
|
|
|
|
}
|
|
|
|
m_absMax = absoluteMax;
|
|
|
|
m_quantizeFactor = rangeMax / shiftedMax;
|
|
|
|
m_inverseQuantizerFactor = 1 / m_quantizeFactor;
|
|
|
|
}
|
2016-06-10 07:54:26 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
}}}
|