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 Bitmap
chw 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.