Partilhar via


CNTK avaliar transformações de imagem

Esta página descreve algumas possíveis implementações para transformar imagens antes de as avaliar numa CNTK modelo que foi treinada com dados alimentados com o ImageReader. Um exemplo de trabalho é fornecido como parte do programa de exemplo CSEvalClient , em particular refere-se ao EvaluateImageClassificationModel método.

Descrição Geral

O plugin imageReader CNTK permite a alimentação de dados de imagem ao CNTK modelo para treino, teste e avaliação. O ImageReader tem algumas capacidades configuráveis que, quando ativados, executam algumas transformações on-the-fly para os dados de imagem. Estas possíveis transformações são:

  • Corte
  • Redimensionar
  • Aplicação da Média
  • Intensidade
  • Cor
  • Layout (HWC vs CHW)

Avaliação de imagem com CNTK.exe e o Leitor de Imagem

Neste caso, as transformações de imagem podem ser especificadas no ficheiro de configuração, e o Imagereader realizará as transformações definidas.

Avaliação programática de imagem através de EvalDll (EvalWrapper)

Neste caso, as transformações de imagem necessárias têm de ser realizadas programáticamente antes de a imagem ser passada para o Evalwrapper.

Esta secção fornece algumas implementações possíveis para a realização de algumas destas transformações antes da avaliação.

Por exemplo, uma classe estática chamada CntkBitmapExtensions poderia conter os métodos de extensão apresentados abaixo.

Redimensionar

    /// <summary>
    /// Resizes an image
    /// </summary>
    /// <param name="image">The image to resize</param>
    /// <param name="width">New width in pixels</param>
    /// <param name="height">New height in pixesl</param>
    /// <param name="useHighQuality">Resize quality</param>
    /// <returns>The resized image</returns>
    public static Bitmap Resize(this Bitmap image, int width, int height, bool useHighQuality)
    {
        var rect = new Rectangle(0, 0, width, height);
        var newImg = new Bitmap(width, height);

        newImg.SetResolution(image.HorizontalResolution, image.VerticalResolution);

        using (var g = Graphics.FromImage(newImg))
        {
            g.CompositingMode = System.Drawing.Drawing2D.CompositingMode.SourceCopy;
            if (useHighQuality)
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
            }
            else
            {
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.Default;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.Default;
                g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.Default;
            }

            var attributes = new ImageAttributes();
            attributes.SetWrapMode(System.Drawing.Drawing2D.WrapMode.TileFlipXY);
            g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attributes);
        }

        return newImg;
    }

Neste caso, uma possível invocação poderia ser:

 var testBitmap = new Bitmap(Bitmap.FromFile(@"C:\rocket.bmp")).Resize(224, 224, true);

Este comando redimensionaria a C:\rocket.bmp imagem para um tamanho de 224 x 224 pixels mantendo uma imagem de alta qualidade.

Conversão de layout de HWC para CHW

Existem principalmente dois tipos de layout usados em CNTK: HWC e CHW. O primeiro, HWC é o formato padrão usado em CNTK. O segundo, CHW, é o formato usado pela cuDNN na GPU.

Note que o layout do ficheiro real pode ser diferente. Estamos a olhar para a representação da memória, não para o conteúdo do ficheiro.

Nota, as descrições acima referem-se à notação de fila-grande comumente utilizada onde a dimensão móvel mais rápida vem em último lugar. CNTK geralmente usa notação de coluna-grande que usa a dimensão móvel mais rápida primeiro e onde o abaixo seria expresso como "CWH" e "WHC", respectivamente.

Isto significa que assumindo um bitmap com formato HWC de tamanho 10x10 usando bytes RGB, o espaço de memória corresponderia a:

Offset (byte) :  0  1  2  3  4  5  6  7  8 ...29 30 31 32 33 34 35 36 37 ...
Height Pos    :  0  0  0  0  0  0  0  0  0 ... 0  0  0  1  1  1  1  1  1 ...
Width Pos     :  0  0  0  1  1  1  2  2  2 ... 9  9  9  0  0  0  1  1  1 ...
Color Index   :  B  G  R  B  G  R  B  G  R ... B  G  R  B  G  R  B  G  R ...

No caso da CHW, o layout seria:

Offset (byte) :  0  1  2  3 ... 9 10 11 12 13 ...90 91 92 93 ... 99 100 ... 199 200 ... 299 
Color Index   :  B  B  B  B ... B  B  B  B  B ... B  B  B  B ...  B   G ...   G   R ...   R
Height Pos    :  0  0  0  0 ... 0  0  0  0  0 ... 9  9  9  9 ...  9   0 ...   9   0 ...   9
Width Pos     :  0  1  2  3 ... 9  0  1  2  3 ... 0  1  2  3 ...  9   0 ...   9   0 ...   9

Um possível método de extensão que extraisse os dados de imagem de um Bitmapchw para o layout chw poderia ser:

    /// <summary>
    /// Extracts image pixels in CHW
    /// </summary>
    /// <param name="image">The bitmap image to extract features from</param>
    /// <returns>A list of pixels in HWC order</returns>
    public static List<float> ExtractCHW(this Bitmap image)
    {
        var features = new List<float>(image.Width * image.Height * 3);
        for (int c = 0; c < 3; c++)
        {
            for (int h = 0; h < image.Height; h++)
            {
                for (int w = 0; w < image.Width; w++)
                {
                    var pixel = image.GetPixel(w, h);
                    float v = c == 0 ? pixel.B : c == 1 ? pixel.G : pixel.R;

                    features.Add(v);
                }
            }
        }

        return features;
    }

O Bitmap.GetPixel método cuida de algumas das nuances de layout da memória, permitindo-nos focar na transformação em si.

Este método pode agora ser usado na nossa transformação de imagem antes da avaliação. Assumindo o mesmo mapa bit que em Resize, poderíamos extrair os seus dados no layout chw com a seguinte invocação:

var features = testBitmap.ExtractCHW();

O features vetor pode agora ser usado como uma entrada de camada na classificação de imagem modelo. Um exemplo de trabalho é fornecido como parte do CSEvalClient programa de exemplo, em particular refere-se ao EvaluateImageClassificationModel método.