Пользовательский слой CoreML: нормализация по пикселям с металлическими шейдерами

Я конвертирую Nvidia Progressive Growing of GAN Generator в coreML. Мне удалось перенести все в coreML, за исключением слоя Pixelwise Normalization (Lambda), который я планирую реализовать в качестве пользовательского слоя coreML в Swift / Metal.

В TensorFlow.Keras я внедрил пиксельную норму как

def pixelwise_norm(a):
return a / tf.sqrt(tf.reduce_mean(a * a, axis=3, keep_dims=True) + 1e-8)

Теперь я едва работал с шейдерами / металлом, но следуя инструкциям здесь: http://machinethink.net/blog/coreml-custom-layers/, У меня есть пользовательский слой, настроенный для использования металла для операций обратной связи. Я использую MTLComputePipelineState, который (вызывает? Кодирует?) Следующий шейдер для операций слоя:

#include <metal_stdlib>
using namespace metal;kernel void pixelwise_norm(
texture2d_array<half, access::read> inTexture [[texture(0)]],
texture2d_array<half, access::write> outTexture [[texture(1)]],
ushort3 gid [[thread_position_in_grid]])
{
if (gid.x >= outTexture.get_width() ||
gid.y >= outTexture.get_height()) {
return;
}

const float4 x = float4(inTexture.read(gid.xy, gid.z));
const float4 y = 0.0000001f + (x / sqrt(pow(x,2)));
outTexture.write(half4(y), gid.xy, gid.z);
}

У меня возникли проблемы с вычислением металлического эквивалента «redu_mean», сейчас этот шейдер реализует операцию

return a / tf.sqrt((a * a) + 1e-8)

У кого-нибудь есть указатели?
Спасибо

0

Решение

Если я правильно читаю, для каждого пикселя в карте объектов это делит этот пиксель на норму L2 по каналам этого пикселя?

В этом случае вам нужно использовать цикл for для чтения каналов для этого пикселя, суммировать эти числа и делить на количество каналов. (Вам нужно сделать этот цикл, только если количество каналов больше 4.)

Также обратите внимание, что ваш 1e-8 должен быть внутри sqrt () или хотя бы в знаменателе.

0

Другие решения

Других решений пока нет …