你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

CNTK评估图像转换

本页介绍在评估图像之前转换图像的一些可能实现,该模型是使用使用 ImageReader 馈送的数据训练的CNTK模型。 作为 CSEvalClient 示例程序的一部分提供工作示例,特别是引用该方法EvaluateImageClassificationModel

概述

CNTK ImageReader 插件支持将图像数据馈送到用于训练、测试和评估的CNTK模型。 ImageReader 具有一些可配置的功能,可在启用时对图像数据执行一些实时转换。 这些可能的转换包括:

  • 裁剪
  • 调整大小
  • 应用平均值
  • 强度
  • 颜色
  • 布局 (HWC 与 CHW)

使用CNTK.exe和图像读取器进行图像评估

在这种情况下,可以在配置文件中指定映像转换,Imagereader 将执行定义的转换。

通过 EvalDll (EvalWrapper) 编程图像评估

在这种情况下,必须在映像传递到 Evalwrapper 之前以编程方式执行所需的映像转换。

本部分提供一些可能的实现,用于在评估之前执行其中一些转换。

例如,名为 CntkBitmapExtensions 的静态类可以包含如下所示的扩展方法。

调整大小

    /// <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;
    }

在这种情况下,可能的调用可能是:

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

此命令会将图像的大小调整 C:\rocket.bmp 为 224 x 224 像素,以维持高质量的图像。

从 HWC 到 CHW 的布局转换

CNTK中主要使用两种布局类型:HWC 和 CHW。 第一种是CNTK中使用的默认格式。 第二个 CHW 是 GPU 中 cuDNN 使用的格式。

请注意,实际 文件 布局 可能 有所不同。 我们正在查看内存表示形式,而不是文件内容

请注意,上述说明是指最常用的 行主 表示法,其中移动速度最快的维度是最后一个。 CNTK通常使用列主表示法,该表示法首先使用最快的移动维度,其中下面分别表示为“CWH”和“WHC”。

这意味着,假设使用 RGB 字节的 HWC 格式为 10x10 的位图,内存空间将对应于:

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

对于 CHW,布局为:

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

将图像数据提取 Bitmap到 CHW 布局的可能扩展方法可以是:

    /// <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;
    }

该方法 Bitmap.GetPixel 负责某些内存布局细微差别,使我们能够专注于转换本身。

在评估之前,可以在图像转换中使用此方法。 假设与 Resize 中的位图相同,我们可以使用以下调用在 CHW 布局中提取其数据:

var features = testBitmap.ExtractCHW();

features现在可将矢量用作图像分类模型中的层输入。 作为示例程序的一部分 CSEvalClient 提供工作示例,特别是引用该方法 EvaluateImageClassificationModel