2016-11-15 1 views
1

спросил Также здесь не повезло (https://groups.google.com/forum/#!topic/android-developers/Rh_L9Jv_S8Q)Копирование с половинной точности распределения F16 в андроида (Renderscript)

Я пытаюсь выяснить, как сделать половину точности с использованием типов, как half и half4. Кажется, что единственная проблема заключается в получении чисел от java до renderscript и обратно.

Java-код:

private float[] input; 
private float[] half_output; 
private RenderScript mRS; 
private ScriptC_mono mScript; 
private final int dimen = 15; 
... 

//onCreate 
input = new float[dimen * dimen * 3];  //later loaded from file 182.24 3.98 105.83 226.08 15.2 80.01... 
half_output = new float[dimen * dimen * 3]; 
... 

//function calling renderscript 
mRS = RenderScript.create(this); 
ScriptC_halfPrecision mScript = new ScriptC_halfPrecision(mRS); 

Allocation input2 = Allocation.createSized(mRS, Element.F16(mRS), dimen * dimen * 3); 
input2.copyFromUnchecked(input);   //copy float values to F16 allocation 

Allocation halfIndex = Allocation.createSized(mRS, Element.F16(mRS), dimen * dimen); 
Type.Builder half_output_type = new Type.Builder(mRS, Element.F16(mRS)).setX(dimen * dimen * 3); 
Allocation output3 = Allocation.createTyped(mRS, half_output_type.create()); 

mScript.set_half_in(input2); 
mScript.set_half_out(output3); 
mScript.forEach_half_operation(halfIndex); 

output3.copy1DRangeToUnchecked(0, dimen * dimen * 3, half_output); //copy F16 allocation back to float array 

Renderscript:

#pragma version(1) 
#pragma rs java_package_name(com.example.android.rs.hellocompute) 

rs_allocation half_in; 
rs_allocation half_out; 

half __attribute__((kernel)) half_operation(uint32_t x) { 
    half4 out = rsGetElementAt_half4(half_in, x); 

    out.x /= 2.0; 
    out.y /= 2.0; 
    out.z /= 2.0; 
    out.w /= 2.0; 

    rsSetElementAt_half4(half_out, out, x); 
} 

Я также попытался это вместо последней строки, показанной в коде Java:

float temp_half[] = new float[1]; 
for (int i = 0; i < dimen * dimen * 3; ++i) {  //copy F16 allocation back to float array 
    output3.copy1DRangeToUnchecked(i, 1, temp_half); 
    half_output[i]=temp_half[0]; 
} 

Al l приведенный выше код отлично работает для float4 переменных в значениях renderscript и F32 в java. Это, очевидно, связано с тем, что проблема не возникает из renderscript float в java float. Но попытка перейти от java float (так как нет java half) для renderscript half и обратно очень сложно. Может ли кто-нибудь сказать мне, как это сделать?

Оба вышеуказанных варианта кода Java приводят к кажущимся случайным значениям в массиве half_output. Они, очевидно, не являются случайными, потому что они являются одинаковыми значениями каждый раз, когда я запускаю его, независимо от того, какая операция в функции half_operation(uint32_t x). Я попытался изменить out.x /= 2.0; (и соответствующие y, z, w код) на out.x /= 2000000.0; или out.x *= 2000000.0; , и все же значения, которые входят в массив half_output, одинаковы при каждом запуске.

Используя вход 182.24 3.98 105.83 226.08 15.2 80.01...

С помощью этого Java

output3.copy1DRangeToUnchecked(0, dimen * dimen * 3, half_output); //copy F16 allocation back to float array 

Полученный half_output является 46657.44 27094.48 3891.45 965.1825 36223.44 14959.08...

С помощью этого Java

float temp_half[] = new float[1]; 
for (int i = 0; i < dimen * dimen * 3; ++i) {  //copy F16 allocation back to float array 
    output3.copy1DRangeToUnchecked(i, 1, temp_half); 
    half_output[i]=temp_half[0]; 
} 

Полученный half_output является 2.3476E-41 2.5546E-41 6.2047E-41 2.5407E-41 1.9802E-41 2.4914E-41...

Снова это результаты независимо от того, что я изменяю алгоритм out.x /= 2.0;.

ответ

0

проблема эта копия не делает преобразование. Он просто поместит ваши исходные значения FP32 в память, но затем, когда вы попытаетесь интерпретировать эти значения как FP16, они будут неверными.

input2.copyFromUnchecked(input);   //copy float values to F16 allocation 

Вы можете порт что-то вроде ответа от этого вопроса до Renderscript:

32-bit to 16-bit Floating Point Conversion

Если вход не имеет denorms/бесконечность/нан/перелива/Underflow это кажется ОК раствор:

uint32_t x = *((uint32_t*)&f); 
uint16_t h = ((x>>16)&0x8000)|((((x&0x7f800000)-0x38000000)>>13)&0x7c00)|((x>>13)&0x03ff); 

Действительно, решение должно содержать исходные значения в файле в двоичном формате fp16. Прочитайте их в массиве java byte [], а затем сделайте копию в распределении ввода fp16. Затем, когда ядро ​​renderscript интерпретирует их как fp16, тогда у вас не должно быть проблем.

Смежные вопросы