/// <summary> /// Given an element dimensions indices [N,H,W,C] return this element offset in memory. /// </summary> public int Index(int b, int h, int w, int ch) { return(shape.Index(b, h, w, ch)); }
Tensor[] PrepareConv2dWinograd(Model model, Layer l) { var K = l.datasets[0]; var Kshape = new TensorShape(K.shape.batch + 1, K.shape.height + 1, K.shape.width, K.shape.channels); var B = l.datasets[1]; var Bshape = B.shape; var weights = new float[Kshape.length + Bshape.length]; for (int c = 0; c < Kshape.kernelDepth; ++c) { for (int k = 0; k < Kshape.kernelCount; ++k) { float g00 = l.weights[K.offset + K.shape.Index(0, 0, c, k)]; float g01 = l.weights[K.offset + K.shape.Index(0, 1, c, k)]; float g02 = l.weights[K.offset + K.shape.Index(0, 2, c, k)]; float g10 = l.weights[K.offset + K.shape.Index(1, 0, c, k)]; float g11 = l.weights[K.offset + K.shape.Index(1, 1, c, k)]; float g12 = l.weights[K.offset + K.shape.Index(1, 2, c, k)]; float g20 = l.weights[K.offset + K.shape.Index(2, 0, c, k)]; float g21 = l.weights[K.offset + K.shape.Index(2, 1, c, k)]; float g22 = l.weights[K.offset + K.shape.Index(2, 2, c, k)]; // float4x3 Winograd_G = float4x3(float3(1, 0, 0), float3(0.5, 0.5, 0.5), float3(0.5, -0.5, 0.5), float3(0, 0, 1)); // float3x4 Winograd_GT = transpose(Winograd_G); // float4x4 v = mul(Winograd_G, mul(g, Winograd_GT)); float w00 = g00; float w01 = 0.5f * g00 + 0.5f * g01 + 0.5f * g02; float w02 = 0.5f * g00 - 0.5f * g01 + 0.5f * g02; float w03 = g02; float w10 = g10; float w11 = 0.5f * g10 + 0.5f * g11 + 0.5f * g12; float w12 = 0.5f * g10 - 0.5f * g11 + 0.5f * g12; float w13 = g12; float w20 = g20; float w21 = 0.5f * g20 + 0.5f * g21 + 0.5f * g22; float w22 = 0.5f * g20 - 0.5f * g21 + 0.5f * g22; float w23 = g22; float v00 = w00; float v01 = w01; float v02 = w02; float v03 = w03; float v10 = 0.5f * w00 + 0.5f * w10 + 0.5f * w20; float v11 = 0.5f * w01 + 0.5f * w11 + 0.5f * w21; float v12 = 0.5f * w02 + 0.5f * w12 + 0.5f * w22; float v13 = 0.5f * w03 + 0.5f * w13 + 0.5f * w23; float v20 = 0.5f * w00 - 0.5f * w10 + 0.5f * w20; float v21 = 0.5f * w01 - 0.5f * w11 + 0.5f * w21; float v22 = 0.5f * w02 - 0.5f * w12 + 0.5f * w22; float v23 = 0.5f * w03 - 0.5f * w13 + 0.5f * w23; float v30 = w20; float v31 = w21; float v32 = w22; float v33 = w23; weights[Kshape.Index(0, 0, c, k)] = v00; weights[Kshape.Index(1, 0, c, k)] = v10; weights[Kshape.Index(2, 0, c, k)] = v20; weights[Kshape.Index(3, 0, c, k)] = v30; weights[Kshape.Index(0, 1, c, k)] = v01; weights[Kshape.Index(1, 1, c, k)] = v11; weights[Kshape.Index(2, 1, c, k)] = v21; weights[Kshape.Index(3, 1, c, k)] = v31; weights[Kshape.Index(0, 2, c, k)] = v02; weights[Kshape.Index(1, 2, c, k)] = v12; weights[Kshape.Index(2, 2, c, k)] = v22; weights[Kshape.Index(3, 2, c, k)] = v32; weights[Kshape.Index(0, 3, c, k)] = v03; weights[Kshape.Index(1, 3, c, k)] = v13; weights[Kshape.Index(2, 3, c, k)] = v23; weights[Kshape.Index(3, 3, c, k)] = v33; } } Buffer.BlockCopy(weights, Kshape.length, l.weights, (int)B.offset, B.length); ComputeBuffer buffer = new ComputeBuffer(Kshape.length + Bshape.length, sizeof(float)); buffer.SetData(weights); var Kw = new Tensor(Kshape, new SharedComputeTensorData(buffer, Kshape, 0)); var Bw = new Tensor(Bshape, new SharedComputeTensorData(buffer, Bshape, Kshape.length)); return(new Tensor[] { Kw, Bw }); }
private static void FillCacheFromTexture(float[] output, Texture tex, int batchOffset, int channelOffset, int[] channelWriteMask, int[] channelReadMap, bool flipY, Vector4 scale4, Vector4 bias4, TensorShape texDataShape) { var tex2D = tex as Texture2D; var texArr = tex as Texture2DArray; var tex3D = tex as Texture3D; var rt = tex as RenderTexture; Color[] colors = null; var texDepth = 1; if (tex2D) { colors = tex2D.GetPixels(0); texDepth = 1; } else if (texArr) { colors = texArr.GetPixels(0, 0); texDepth = texArr.depth; } else if (tex3D) { colors = tex3D.GetPixels(0); texDepth = tex3D.depth; } else if (rt) { var currentRT = RenderTexture.active; RenderTexture.active = rt; Texture2D tmpTexture = new Texture2D(rt.width, rt.height, tex.graphicsFormat, TextureCreationFlags.None); tmpTexture.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0); tmpTexture.Apply(); colors = tmpTexture.GetPixels(0); RenderTexture.active = currentRT; texDepth = rt.volumeDepth; if (rt.format == RenderTextureFormat.RHalf) { Debug.LogError( "Texture to Tensor does not support RHalf format for source rendertarget when Compute shader are not available on platform."); } } if (texDepth != 1) { Debug.LogError( "Texture to Tensor only support texture resource with one slice when Compute shader are not available on platform!"); } Assert.IsNotNull(colors); for (int x = 0; x < texDataShape.width; ++x) { for (int yTex = 0; yTex < texDataShape.height; ++yTex) { int c = channelOffset; int y = flipY ? texDataShape.height - yTex - 1 : yTex; var pixelIndex = yTex * texDataShape.width + x; Vector4 v = colors[pixelIndex]; bool specialCaseWhenChannelMaskIsEmptyStoresAverage = true; for (int i = 0; i < 4; ++i) { if (channelWriteMask[i] == 1) { int readFrom = channelReadMap[i]; float value = i < 3 ? 0 : 1; // default values for channels R,G,B=0 and A=1 float scale = 1.0f; float bias = 0.0f; if (readFrom >= 0) { value = v[readFrom]; scale = scale4[readFrom]; bias = bias4[readFrom]; } output[texDataShape.Index(batchOffset, y, x, c)] = scale * value + bias; specialCaseWhenChannelMaskIsEmptyStoresAverage = false; c += 1; } } if (specialCaseWhenChannelMaskIsEmptyStoresAverage) { v = Vector4.Scale(v, scale4) + bias4; float avg = (v.x + v.y + v.z) / 3.0f; output[texDataShape.Index(batchOffset, y, x, c)] = avg; } } } }