I'm facing a problem with tensorflow-lite. I get this error:
Type INT32 (2) not supported.
Node STRIDED_SLICE (number 2) failed to invoke with status 1
What I did was:
I trained a model with MNIST data.
model = tf.keras.Sequential([
tf.keras.layers.InputLayer(input_shape=(28, 28)),
tf.keras.layers.Reshape(target_shape=(28, 28, 1)),
tf.keras.layers.Conv2D(filters=12, kernel_size=(3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(pool_size=(2, 2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(10)
])
I converted the model using integer-only quantization. However, when I invoke the model it
throws that error.
I was looking at the striced_slice.cc and I found this:
switch (output->type) {
case kTfLiteFloat32:
reference_ops::StridedSlice(op_params,
tflite::micro::GetTensorShape(input),
tflite::micro::GetTensorData<float>(input),
tflite::micro::GetTensorShape(output),
tflite::micro::GetTensorData<float>(output));
break;
case kTfLiteUInt8:
reference_ops::StridedSlice(
op_params, tflite::micro::GetTensorShape(input),
tflite::micro::GetTensorData<uint8_t>(input),
tflite::micro::GetTensorShape(output),
tflite::micro::GetTensorData<uint8_t>(output));
break;
case kTfLiteInt8:
reference_ops::StridedSlice(op_params,
tflite::micro::GetTensorShape(input),
tflite::micro::GetTensorData<int8_t>(input),
tflite::micro::GetTensorShape(output),
tflite::micro::GetTensorData<int8_t>(output));
break;
default:
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
TfLiteTypeGetName(input->type), input->type);
So there is not support for int32. I am not really sure how I can handle this kind of problem. Is there any way to change the behavior on this node? Should I do something different in the quantization step?
What I did was:
def representative_data_gen():
for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):
yield [input_value]
converter = tf.lite.TFLiteConverter.from_keras_model(model)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_data_gen
# Ensure that if any ops can't be quantized, the converter throws an error
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8
converter.inference_output_type = tf.int8
tflite_model = converter.convert()
open("model_int8.tflite", "wb").write(tflite_model)
PD: I'm working with tensorflow-lite to be used in stm32.
Thanks in advance.
When you perform full-integer quantization, your inputs and outputs should be 1-byte long (in your case int8). Give as input int8 values and you will be able to invoke your model.
I worked around this issue simply adding INT32 support to striced_slice.cc.
case kTfLiteFloat32:
reference_ops::StridedSlice(op_params,
tflite::micro::GetTensorShape(input),
tflite::micro::GetTensorData<float>(input),
tflite::micro::GetTensorShape(output),
tflite::micro::GetTensorData<float>(output));
break;
case kTfLiteUInt8:
reference_ops::StridedSlice(
op_params, tflite::micro::GetTensorShape(input),
tflite::micro::GetTensorData<uint8_t>(input),
tflite::micro::GetTensorShape(output),
tflite::micro::GetTensorData<uint8_t>(output));
break;
case kTfLiteInt8:
reference_ops::StridedSlice(op_params,
tflite::micro::GetTensorShape(input),
tflite::micro::GetTensorData<int8_t>(input),
tflite::micro::GetTensorShape(output),
tflite::micro::GetTensorData<int8_t>(output));
break;
case kTfLiteInt32:
reference_ops::StridedSlice(op_params,
tflite::micro::GetTensorShape(input),
tflite::micro::GetTensorData<int8_t>(input),
tflite::micro::GetTensorShape(output),
tflite::micro::GetTensorData<int8_t>(output));
break;
default:
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
TfLiteTypeGetName(input->type), input->type);
return kTfLiteError;
I copied the kTfLiteInt8 case and created a kTfLiteInt32 case.
The idea is since I know the input data is actually int8 type, I simply cast it to int8.
I have tested it in an ESP32 microcontroller. I didn't run a full set of test but with a few samples it worked as expected.
This is a workaround. The real fix should be done in the converter where it fully quantize the model by using TFLITE_BUILTINS_INT8. Somehow, it quantize the float32 types but int32 stays in one of the layers.
Related
Not sure if it's a software issue or my incredible programming skills.
I'm using UE4.27 and Rider for UE 2021.2.1 for C++ project. Recently I got some strange bug or something else: some changes in the code do not affect the program in any way. For example, there are old logs (Unable to get Owner Actor, AttackMontageN) that still work fine and new logs (NewLog) that didn't work, but there are no errors while building, crashes or anything like this:
void UMeleeAttackAbility::CommitExecute(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo)
{
Super::CommitExecute(Handle, ActorInfo, ActivationInfo);
const auto Owner = ActorInfo->OwnerActor.Get();
if (!Owner)
{
UE_LOG(LogPRAbilitySystemBase, Error, TEXT("Unable to get Owner Actor"))
K2_EndAbility();
}
UE_LOG(LogPRAbilitySystemBase, Warning, TEXT("NewLog"));
const int MontageIndex = rand() % 3;
switch(MontageIndex)
{
case 0:
UE_LOG(LogPRAbilitySystemBase, Warning, TEXT("AttackMontage1"));
AttackMontage = AttackMontage1;
break;
case 1:
UE_LOG(LogPRAbilitySystemBase, Warning, TEXT("AttackMontage2"));
AttackMontage = AttackMontage2;
break;
case 2:
UE_LOG(LogPRAbilitySystemBase, Warning, TEXT("AttackMontage3"));
AttackMontage = AttackMontage3;
break;
default:
break;
}
UE_LOG(LogPRAbilitySystemBase, Warning, TEXT("NewLog"));
//...
}
I reverted to one very old commit where this code is completely different, but the results in the logs and character behavior are still the same. Also I'm tried to rebuild current project (in Advanced Build Actions) and do some other obvious things such restarting UE4/Rider, etc. Is it Rider problem or it can be something else?
So at work I inherited a massive project taking 1553 messages from an airplane and translating them to a completely different message type. My problem is that I need to use the data from 2 different messages, which are processed completely separately, together.
This is how I inherited it: there's a completely different process for processing the 2Rx message (which has the "plane altitude" data) and the 17Rx message (which has the "structure altitude" data).
I tried to simplify as much of the code that's relevant as possible, but this is the first experience I've had with coding and I've had no programming education, so please tell me if there's something I can do to make it more clear (for example I don't fully understand the Process1553 function).
My job is to do the actual conversions: in my example the altitude data for both the plane and a ground structure is being received in meters and needs to be sent out as feet. However, I ALSO need to send out data comparing the 2 altitudes (well, I'm actually converting Lat/Long/Alt to North/East/Down, but for simplicity let's just say I need the difference in altitudes of the plane and the structure).
void AirplaneComm::Process1553()
{
M1553RawMsgClass *currentMessage;
//check for new messages
while(incomingMessages->size()>0)
{
//grab the message from the top of the stack
currentMessage=(M1553RawMsgClass*)incomingMessages->front();
//pop the stack
incomingMessages->pop_front();
//We are only interested in R messages
if(currentMessage->MessageType()==M1553RawMsgClass::RECEIVE_MSG)
{
M1553RxMsgClass newRxMessage(*currentMessage);
switch (newRxMessage.RxMsgType())
{
case M1553RxMsgClass::RX_2: {
ProcessRx2Msg(newRxMessage);
break;}
// .... more messages
case M1553RxMsgClass::RX_17: {
ProcessRx17Msg(newRxMessage);
break;}
default:
// No processing for this message
break;
}
}
//clean up
if(currentMessage)
{
delete currentMessage;
}
}
}
void AirplaneComm::ProcessRx2Msg(M1553RxMsgClass incoming2Rmessage)
{
M1760Rx2MsgClass newMessage(incoming2Rmessage); //M1760 classes "get" data from
//the 1553 messages and "set"
//it to send as serial
WordType platformAltitudeMeters = newMessage.GetPlatAltitude(); //received altitude in meters
double platformAltitudeFeet = platformAltitudeMeters * 3.2808; //converted to feet
mSerial.SetPlatAltitude(platformAltitudeFeet); //sets the altitude info
}
void AirplaneComm::ProcessRx17Msg(M1553RxMsgClass incoming17Rmessage)
{
M1760Rx17MsgClass newMessage(incoming17Rmessage);
WordType structureAltitudeMeters = newMessage.GetStructAltitude(); //received altitude in meters
double structureAltitudeFeet = structureAltitudeMeters * 3.2808; //converted to feet
mSerial.SetStructAltitude(structureAltitudeFeet); //sets the altitude info
}
So as far as I can tell, the "switch" function takes each "case" individually. I tried creating a new 2Rx AND 17Rx process ("ProcessRx2MsgRx17Msg") assigning those messages (Rx2Msg, Rx17Msg) to variables I declared in each "case":
switch (newRxMessage.RxMsgType())
{
case M1553RxMsgClass::RX_2:
ProcessRx2Msg(newRxMessage);
M1553RxMsgClass Rx2Msg; //M1553RxMsgClass is a variable type taking
Rx2Msg = newRxMessage; //the whole message
break;}
case M1553RxMsgClass::RX_17:
ProcessRx17Msg(newRxMessage);
M1553RxMsgClass Rx17Msg = newRxMessage;
break;
default:
// No processing for this message
break;
ProcessRx2MsgRx17Msg(Rx2Msg, Rx17Msg);
}
but when I did that, it claimed that I was jumping switch labels. I get that this means they are in the same "scope" (ok, I googled it) but when I put brackets around each "case":
case M1553RxMsgClass::RX_2: {
ProcessRx2Msg(newRxMessage);
M1553RxMsgClass Rx2Msg;
Rx2Msg = newRxMessage;
break;}
case M1553RxMsgClass::RX_17: {
ProcessRx17Msg(newRxMessage);
M1553RxMsgClass Rx17Msg = newRxMessage;
break;}
default:
// No processing for this message
break;
ProcessRx2MsgRx17Msg(Rx2Msg, Rx17Msg);
}
but then my ProcessRx2MsgRx17Msg doesn't recognize "Rx2Msg" or "Rx17Msg".
I also considered making "ProcessRx2Msg" a function that could return a value instead of a void function so that I could use it in "ProcessRx17Msg", but I actually need multiple variables from each message (latitude, longitude, and altitude).
So, is it even possible to accomplish what I want with the way it's set up since I inherited it? Also, sorry if I used the wrong terms for certain things.
EDIT: Thank you JarMan and SoronelHaetir. This is how I ended up getting it to work:
void AirplaneComm::Process1553()
{
M1553RawMsgClass *currentMessage;
static M1553RxMsgClass Rx2Msg, Rx17Msg;
//check for new messages
while(incomingMessages->size()>0)
{
//grab the message from the top of the stack
currentMessage=(M1553RawMsgClass*)incomingMessages->front();
//pop the stack
incomingMessages->pop_front();
//We are only interested in R messages
if(currentMessage->MessageType()==M1553RawMsgClass::RECEIVE_MSG)
{
M1553RxMsgClass newRxMessage(*currentMessage);
switch (newRxMessage.RxMsgType())
{
case M1553RxMsgClass::RX_2:
ProcessRx2Msg(newRxMessage);
Rx2Msg = newRxMessage;
break;
// .... more messages
case M1553RxMsgClass::RX_17:
ProcessRx17Msg(newRxMessage);
Rx17Msg = newRxMessage;
ProcessRx2MsgRx17Msg(Rx2Msg, Rx17Msg);
break;
default:
// No processing for this message
break;
}
}
//clean up
if(currentMessage)
{
delete currentMessage;
}
}
}
Then, I was able to use ProcessRx2MsgRx17Msg to convert the airplane geodetic data from Rx2 AND the structure geodetic data from Rx17 to North/East/Down coordinates.
If you need to process data from multiple messages you will have to alter the earlier message processing to save the needed data somewhere then when the later message comes in refer to both the later message parameters as well as the saved message parameters from the earlier message(s). The saved data will need a lifetime longer than the single function call (whether you make it static to the message processing function or global is up to the design choices your organization uses).
I have an c# interface with multiple implementations & each implementation is taking various dependencies object in its constructor.
In order to achieve DI using LightInjector on web api project, Im registering a 'Func' like below & its working as expected but can't able to unit test it.
Any way I can write the below code in unit testable way?
container.RegisterInstance<Func<IHandler, HandlerType, IHandler>>
((handler, type) =>
{
IHandler context = null;
switch (type)
{
case HandlerType.Type0:
context = new Type0(orderHandler, container.GetInstance<IUtilityLogic>());
break;
case HandlerType.Type1:
context = new Type1(orderHandler, container.GetInstance<IUtilityLogic>(), container.GetInstance<IShipmentLogic>());
break;
case HandlerType.Type2:
context = new Type2(orderHandler);
break;
case HandlerType.Type3:
context = new Type3(orderHandler, container.GetInstance<IUtilityLogic>());
break;
case HandlerType.Type4:
context = new Type4(orderHandler, container.GetInstance<IUtilityLogic>(), container.GetInstance<IShipmentLogic>(), container.GetInstance<Func<string, string, ICache>>());
break;
default:
context = null;
break;
}
return context;
});
I`ve encountered a problem:
Is it possible, to use regexp as a key in hashmap?
For example:
def unitsMap=[
(~/(?i).*ABC.*nM.*/):'AAA',
(~/(?i).*DEF.*nM.*/):'DDD'
]
println unitsH3HashMap['ABC (122344345P)']
Of course, that returns null value.
Best regards
No, but you can use it in a switch:
def unitsMap(key) {
switch(key) {
case ~/(?i).*ABC.*/: return 'AAA'
case ~/(?i).*DEF.*/: return 'DDD'
}
}
println unitsMap('ABC (122344345P)')
In order to get what you want you would have to write your own implementation of Map that uses pattern matching to perform getAt, putAt, contains, etc. However, it seems to me that the algorithmic complexity for lookups in such a scenario would always be O(n). Not very good compared to HashMap (O(0)) or TreeMap (O(log n)).
#tim_yates 's solution solves the raw outline of the problem as presented, but would not allow you to add new keys (cases) on-the-fly, as would your original desired code. If on-the-fly changes to your "map" are not important to you, then you should definitely use his solution (which I will endorse by giving it +1 now). If not, the you might be able to adapt his code to generate and invoke a script from a Map that will do what you desire.
This script:
// generate unitMapper
def generateUnitMapper(baseMap) {
def script = '''{ key ->
switch (key) {
'''
script += baseMap.collect { k, v ->
""" case ~/${k}/: return '${v}'
"""
}.join("")
script += ''' default: return null
}
}
'''
}
// notice this map is just using the regular expression STRINGS as keys,
// not the PATTERN objects from the original poster's code
def starterMap = [
/(?i).*ABC.*[\dA-Z]+.*/:'AAA',
/(?i).*DEF.*[\dA-Z]+.*/:'DDD'
]
def closureScript = generateUnitMapper(starterMap)
def unitsClosure = Eval.me(closureScript)
println closureScript
println unitsClosure('ABC (122344345P)')
println()
// regenerate map and closure and rerun
def changedMap = [ /ABC .*/:'000' ] + starterMap
closureScript = generateUnitMapper(changedMap)
unitsClosure = Eval.me(closureScript)
println closureScript
println unitsClosure('ABC (122344345P)')
Yields this output:
{ key ->
switch (key) {
case ~/(?i).*ABC.*[\dA-Z]+.*/: return 'AAA'
case ~/(?i).*DEF.*[\dA-Z]+.*/: return 'DDD'
default: return null
}
}
AAA
{ key ->
switch (key) {
case ~/ABC .*/: return '000'
case ~/(?i).*ABC.*[\dA-Z]+.*/: return 'AAA'
case ~/(?i).*DEF.*[\dA-Z]+.*/: return 'DDD'
default: return null
}
}
000
In the Xcode 5 (and probably 4) project settings -
How can we find out what 'Compiler Default' actually resolves to for the Apple LLVM - Language - C++ setting?
According to the "Quick Help Inspector" in Xcode 5.0.2, the current "Compiler Default" is "GNU++98", which corresponds to the compiler option "-std=gnu++98".
It can also be seen in the compiler source code (http://clang.llvm.org/doxygen/CompilerInvocation_8cpp_source.html, line 01057):
01033 if (LangStd == LangStandard::lang_unspecified) {
01034 // Based on the base language, pick one.
01035 switch (IK) {
01036 case IK_None:
01037 case IK_AST:
01038 case IK_LLVM_IR:
01039 llvm_unreachable("Invalid input kind!");
01040 case IK_OpenCL:
01041 LangStd = LangStandard::lang_opencl;
01042 break;
01043 case IK_CUDA:
01044 LangStd = LangStandard::lang_cuda;
01045 break;
01046 case IK_Asm:
01047 case IK_C:
01048 case IK_PreprocessedC:
01049 case IK_ObjC:
01050 case IK_PreprocessedObjC:
01051 LangStd = LangStandard::lang_gnu99;
01052 break;
01053 case IK_CXX:
01054 case IK_PreprocessedCXX:
01055 case IK_ObjCXX:
01056 case IK_PreprocessedObjCXX:
01057 LangStd = LangStandard::lang_gnucxx98;
01058 break;
01059 }
01060 }