es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo interpretar el resultado de MLMultiArray en segmentación semántica a través de CoreML?

Estoy tratando de implementar un modelo de segmentación semántica en mi aplicación. He logrado convertir el modelo u2net a un modelo CoreML. No puedo obtener un resultado funcional a partir de la salida MLMultiArray. La descripción de la especificación es la siguiente:

Entrada:
nombre: “input”
tipo:
tipo de imagen:
ancho: 512
alto: 512
espacio de color: RGB

Salida:
nombre: “x_1”
tipo:
tipo de matriz múltiple:
forma: 1
forma: 3
forma: 512
forma: 512
dataType: FLOAT32

El modelo funciona muy bien al abrirlo y utilizar la funcionalidad de vista previa del modelo en Xcode. Muestra las 2 etiquetas diferentes en 2 colores (solo hay 2 clases + 1 fondo). Quiero tener la misma salida en mi aplicación, sin embargo, cuando proceso manualmente la salida de MLMultiArray a una CGImage obtengo resultados diferentes. Estoy utilizando el código proporcionado en https://github.com/powermobileweb/CoreMLHelpers de la siguiente manera:

let image = output.cgImage(min: -1, max: 1, channel: 0, axes: (1,2,3))

Esto me da algo que se ve utilizable pero tiene mucho desvanecimiento dentro de cada canal. Lo que necesito es una imagen con solo un valor de color para cada etiqueta.

He intentado convertir la salida del modelo directamente a una imagen a través de este código de muestra (https://developer.apple.com/forums/thread/81571#241998). Esto simplemente muestra “Error en la inferencia” en la vista previa del modelo de Xcode. Cuando intento eliminar la dimensión adicional innecesaria en la salida de MultiArray, obtengo este error:

“Error leyendo la especificación protobuf. Error del validador: la capa ‘x_1’ de tipo ‘Convolution’ tiene un rango de salida 3 pero espera un rango de al menos 4.”

¿Qué hace la vista previa del modelo en Xcode que yo no estoy haciendo? ¿Hay un paso de posprocesamiento que debo seguir para obtener una salida utilizable?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Solución para implementar un modelo de segmentación semántica en una aplicación

    Para implementar un modelo de segmentación semántica en una aplicación utilizando CoreML, se pueden seguir los siguientes pasos:

    1. Convertir el modelo u2net a un modelo de CoreML.
    2. Utilizar la funcionalidad de vista previa del modelo en Xcode para asegurarse de que está funcionando correctamente.
    3. Procesar la salida MLMultiArray del modelo a una CGImage utilizando el siguiente código proporcionado:
      let image = output.cgImage(min: -1, max: 1, channel: 0, axes: (1,2,3))
      
    4. Convertir la salida del modelo directamente a una imagen utilizando el código proporcionado en el [Foro de Desarrolladores de Apple][2].
    5. Si es necesario, eliminar dimensiones adicionales innecesarias de la salida MultiArray. Sin embargo, es importante tener en cuenta que cambiar las dimensiones de salida del modelo puede causar errores.

    La especificación de la output proporcionada en la pregunta describe un modelo que recibe una imagen RGB con dimensiones de 512×512 píxeles y devuelve una salida MultiArray. La salida MultiArray tiene 3 dimensiones (con tipo de datos FLOAT32) que representan las 2 etiquetas diferentes y el fondo.

    Al procesar la salida MLMultiArray a una CGImage, es importante tener en cuenta que el código proporcionado escala los valores de salida al rango de -1 a 1. Esto puede causar gradiente dentro de cada canal, aunque la imagen se vea útil de alguna manera.

    Para obtener una imagen con un color único para cada etiqueta, se requiere un paso de post-procesamiento. Una forma de lograr esto es aplicar un mapa de colores a los valores de salida. Se puede utilizar el siguiente código para esto:

    func colormap(_ l: Int) -> (Int, Int, Int) {
        switch l {
        case 1: // etiqueta 1 (por ejemplo, primer plano)
            return (0, 255, 0) // verde
        case 2: // etiqueta 2 (por ejemplo, fondo)
            return (255, 0, 0) // rojo
        default: // fondo
            return (0, 0, 0) // negro
        }
    }
    
    let width = output.shape[2]
    let height = output.shape[3]
    let bytesPerPixel = 4 // RGBA
    let bytesPerRow = width * bytesPerPixel
    let bitsPerComponent = 8
    let colorSpace = CGColorSpaceCreateDeviceRGB()
    let context = CGContext(data: nil,
                            width: width,
                            height: height,
                            bitsPerComponent: bitsPerComponent,
                            bytesPerRow: bytesPerRow,
                            space: colorSpace,
                            bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
    context.draw(output)
    
    let label = UnsafePointer<float32>(OpaquePointer(output.dataPointer))
    var data = [UInt8](repeating: 0, count: height * width * bytesPerPixel)
    
    for y in 0..<height {="" for="" x="" in=""></height><width {="" let="" offset="y" *="" width="" +="" x="" let="" idx="offset" *="" 3="" let="" l="Int(label[idx" +="" 1]=""> label[idx + 2] ? 1 : 2) // obtener etiqueta con mayor probabilidad
            let (r, g, b) = colormap(l)
            data[offset * bytesPerPixel] = UInt8(r)
            data[offset * bytesPerPixel + 1] = UInt8(g)
            data[offset * bytesPerPixel + 2] = UInt8(b)
            data[offset * bytesPerPixel + 3] = 255 // alfa
        }
    }
    
    let outp = UnsafeMutablePointer<uint8>(mutating: data)
    let out_ctx = CGContext(data: outp,
                            width: width,
                            height: height,
                            bitsPerComponent: bitsPerComponent,
                            bytesPerRow: bytesPerRow,
                            space: colorSpace,
                            bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue)!
    
    if let cgimg = out_ctx.makeImage() {
        let out_image = UIImage(cgImage: cgimg)
    }
    

    Este código utiliza la función colormap para asignar a cada etiqueta un color específico. La línea context.draw(output) se utiliza para dibujar la salida MLMultiArray en un contexto de gráficos principales. Luego, la variable label se utiliza para obtener la etiqueta con la mayor probabilidad y asignarle un color utilizando la función colormap. Por último, se crea la imagen de salida utilizando los datos RGB modificados.

Comments are closed.