2016-11-15 72 views
1

這裏還問有沒有運氣(https://groups.google.com/forum/#!topic/android-developers/Rh_L9Jv_S8Q複製並針對Android(的renderScript)半精度F16分配

我試圖找出如何使用類型,如halfhalf4做半精度。唯一的問題似乎是從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上面的代碼完美適用於在java中的renderscript和F32分配中的float4變量。 這顯然是因爲從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

如果輸入沒有非正規化/無限遠/南/溢/下溢,這似乎是一個確定解決方案:

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時,你應該沒有問題。