Azure Machine Learning で色のクラスタリング (1)

最近ついに正式版となった Microsoft Azure Machine Learning では、
次に挙げるようなさまざまな種類の機械学習アルゴリズムをクラウドの PaaS として利用できます。

  • Supervised Learning (教師あり学習)
    • Classification (分類)
          非連続値を対象とする場合
          two-class (二値) と multi-class (多値) がある
    • Regression (回帰)
          連続値を対象とする場合
  • Unsupervised Learning (教師なし学習)
    • Clustering (クラスタリング)
    • Recommendation (レコメンデーション)

このほか、GUI ベースでモデリングできることや Web API として迅速に公開できることなども特徴です。

 

以下では Microsoft Azure Machine Learning を利用して、色のデータをクラスタリングしてみます。
今回は、色相を基準にクラスタリングして、その結果をストレージに出力することにします。

まず、次のコンソール アプリケーションにより、System.Drawing.Color で定義されている色のデータセットを作成します。

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reflection;
namespace ColorDataConsole
{
static class Program
{
static void Main(string[] args)
{
var columnNames = "RGB,Name,R,G,B,Hue,Saturation,Brightness";
var colorData = typeof(Color).GetProperties(BindingFlags.Public | BindingFlags.Static)
.Where(p => p.PropertyType == typeof(Color))
.Select(p => (Color)p.GetValue(null))
.Where(c => c.A == 255) // Exclude Transparent.
.Select(c => string.Join(",", string.Format("#{0:X2}{1:X2}{2:X2}", c.R, c.G, c.B), c.Name, c.R, c.G, c.B, c.GetHue().ToString("N6"), c.GetSaturation().ToString("N6"), c.GetBrightness().ToString("N6")));
File.WriteAllLines("ColorData.csv", new[] { columnNames }.Concat(colorData));
}
}
}
view raw Program.cs hosted with ❤ by GitHub

これを実行して、140 件の色のデータ ファイル (ColorData.csv) ができました。
(Cyan と Aqua はともに #00FFFF、Magenta と Fuchsia はともに #FF00FF で同じ色です。)

image

 

では次に、Azure の管理ポータルで、Machine Learning のワークスペースを作成します。

image

作成が完了したら、ワークスペースを選択して [Studio で開く] をクリックします。
これで、Machine Learning Studio が新しいタブで開きます。

image

 

ここからは Machine Learning Studio での操作です。

Experiment を作成する前にまず、データセットをアップロードしておきましょう。
先ほどの CSV ファイルを選択します。
アップロードすると、自動的にストレージにコンテナーが作成され、そこにファイルが保存されます。

image

次に、本題の [Blank Experiment] を作成します。
(なお、多くのサンプルが用意されているので、いろいろ試してみると理解につながるでしょう。)

image

 

この Experiment でモデリングや実行ができます。
まず、[Saved Datasets] から [ColorData.csv] を選べるようになっているので、
これを中央のスペースにドラッグ アンド ドロップします。

image

 

残りのモジュールもドラッグ アンド ドロップで配置していきます。とりあえずは、次のように配置します。
各モジュールには ○ の部分があり、上側は入力、下側は出力を表しています。
それぞれを矢印で結ぶには、○ の部分を始点から終点までドラッグします。

image

クラスタリングで選べるアルゴリズムは [K-Means Clustering] (k 平均法) のみです。
プロパティの [Number of Centroids] はクラスターの数を表します。
この値は実行時に決まるわけではなく、あらかじめ指定されなければなりません。
今回は 10 に設定しておきます。

image

[Execute R Script] では、次のスクリプトを指定します。
元の色データでは、Saturation (彩度) が 0 の色の Hue (色相) が 0 になってしまっているため、
赤とグレースケールが混同してしまいます。
そこで、グレースケールの Hue を便宜的に -60 に補正します。

ds <- maml.mapInputPort(1) # class: data.frame
ds$Hue <- ifelse(ds$Hue == 0 & ds$Saturation == 0, -60, ds$Hue)
maml.mapOutputPort("ds");
view raw correct-hue.r hosted with ❤ by GitHub

[Train Clustering Model] では、クラスタリングに用いるための特徴を指定する必要があります。
[Launch column selector] をクリックします。

image

今回は、とりあえず色相のみで判定させることにします。Hue のみを選択します。

image

ここでいったん、[Run] をクリックして Experiment を実行します。
実行が完了すると、緑色のチェック マークが付きます。
これで、クラスタリング モデルの学習までできました。

image

 

結果を出力するため、モジュールを 2 つ追加します。

image

[Project Columns] では、最終的に出力する列を絞ります。
Assignments 列に、実行結果のクラスターの番号が入ります。
なお、先ほどの時点で Experiment を実行しておかないと、列名の候補が自動で出てきません。
こまめに実行しながらモデリングを進めるとよいでしょう。

image

 

ここで、いったん Azure 管理ポータルに戻り、結果データの出力先となるコンテナーをストレージに作成しておきます。

image

[Writer] に出力先の情報を設定します。
アカウント情報は、ストレージのダッシュボードの [アクセスキーの管理] から取得できます。

image

 

これで一通り完成したので実行します。
完了すると、コンテナーに結果データ (CSV) が保存されます。

image

なお、実行が完了している場合、
各モジュールの出力 (下側の ○ の部分) を右クリックするとコンテキスト メニューが有効になります。

image

[Visualize] を選択すると、出力結果を表やグラフで見ることができます。

image

 

次回は、出力結果の色データの視覚化と、学習済みクラスタリング モデルの利用についてです。

次回: Azure Machine Learning で色のクラスタリング (2)

作成したサンプル
Clustering Colors 1: by Hue (Azure ML Gallery)
AzureMLSample (GitHub)

参照
Microsoft Azure Machine Learning Gallery
Machine Learning Studio とは
How to choose an algorithm in Azure Machine Learning

XAML でリキッド レイアウト

リキッド レイアウト (liquid layout) とは、表示領域のサイズによって動的に表示方法が最適化されるようなレイアウトを指します。

もしレイアウトについてとくに意識せずに固定サイズのアプリケーションを実装してしまうと、
ウィンドウのサイズが小さい場合には一部のコンテンツが隠れたり、
逆にウィンドウのサイズが大きい場合には空白ができたりしてしまいます。

ディスプレイの解像度の制限やユーザーによるウィンドウのサイズ変更など、
表示領域のサイズの連続的な変化に対応しなければなりません。

以下では、XAML 系アプリケーションでリキッド レイアウトを実現するためのパターンと実装例を紹介します。

(1) Grid

Grid では、ColumnDefinitions プロパティおよび RowDefinitions プロパティにより、各行・列の幅を指定できます。
固定値のほか、他の行・列との相対値 (1:2 にする場合など) や内部のコンテンツの幅 (Auto) も指定できます。

(2) ScrollViewer

ScrollViewer を利用すれば、スクロールにより全体を表示させることができます。
コレクション データを扱う場合は、ScrollViewer と WrapPanel を組み合わせて使うとよいでしょう。
ちなみに ScrollViewer は、既定で縦スクロールバーが有効、横スクロールバーが無効に設定されています。

(3) Viewbox

Viewbox は、表示領域に合わせて内部のコンテンツを伸縮させることにより、元のレイアウトを保持します。
最も手っ取り早い方法かもしれません。

(4) 最大値・最小値の指定

Viewbox のような伸縮させるコントロールでは、既定では無制限にコンテンツが拡大・縮小してしまいます。
したがって、サイズの最大値・最小値を指定する方法も有効です。

 

これらのパターンを実装する例として、次の WPF アプリケーションを作成しました。

using System;
using System.Collections.Generic;
using System.Linq;
namespace LayoutWpf
{
public class AppModel
{
public int[] Numbers { get; private set; }
public AppModel()
{
Numbers = Enumerable.Range(1, 15).ToArray();
}
}
}
view raw AppModel.cs hosted with ❤ by GitHub
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
xmlns:local="clr-namespace:LayoutWpf" x:Class="LayoutWpf.MainWindow"
Title="MainWindow" Width="900" Height="600" FontSize="32">
<Window.Resources>
<ItemsPanelTemplate x:Key="NumbersPanelTemplate">
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
<DataTemplate x:Key="NumberDataTemplate">
<TextBlock Text="{Binding Mode=OneWay, StringFormat=No.\{0\}}" Width="120" TextAlignment="Center"/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:AppModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Margin="20" Background="#FFEECCBB">
<ItemsControl ItemsSource="{Binding Numbers}" ItemsPanel="{DynamicResource NumbersPanelTemplate}" ItemTemplate="{DynamicResource NumberDataTemplate}"/>
</Grid>
<ScrollViewer Grid.Column="1" Margin="20" Background="#FFCCEEBB">
<ItemsControl ItemsSource="{Binding Numbers}" ItemsPanel="{DynamicResource NumbersPanelTemplate}" ItemTemplate="{DynamicResource NumberDataTemplate}"/>
</ScrollViewer>
<Viewbox Grid.Row="1" Margin="20">
<Grid Width="390" Height="260" Background="#FFBBCCEE">
<ItemsControl ItemsSource="{Binding Numbers}" ItemsPanel="{DynamicResource NumbersPanelTemplate}" ItemTemplate="{DynamicResource NumberDataTemplate}"/>
</Grid>
</Viewbox>
<Grid Grid.Row="1" Grid.Column="1" Margin="20" Background="#FFFFEEBB">
<Viewbox MaxWidth="360" HorizontalAlignment="Left" VerticalAlignment="Top">
<Grid Width="360" Background="LightGray">
<ItemsControl ItemsSource="{Binding Numbers}" ItemsPanel="{DynamicResource NumbersPanelTemplate}" ItemTemplate="{DynamicResource NumberDataTemplate}"/>
</Grid>
</Viewbox>
</Grid>
</Grid>
</Window>
view raw MainWindow.xaml hosted with ❤ by GitHub

(全体のソースコードは GitHub の LayoutWpf にあります。)

 

ここでは 4 つの表示領域があり、
左上はとくに何も対策しない例、右上は ScrollViewer を使う例、
左下は Viewbox を使う例、右下は Viewbox の横幅に最大値を指定する例です。

各領域では、内部のコンテンツとしてコレクション データを ItemsControl で表示させています。
この ItemsControl の ItemsPanel を WrapPanel に設定しています。

また、この 4 つの表示領域は 2×2 の Grid 上にあり、行も列も 1:1 に分割されています。

このアプリケーションを起動するとこうなります。

起動時の状態

 

ウィンドウのサイズを小さくします。
左上および右上では WrapPanel の列の数が減りますが、
左上では、下部を表示することができません。右上では、スクロールすれば残りが表示されます。
左下と右下では Viewbox に合わせてコンテンツが縮小されます。

小さくした状態

 

今度は、ウィンドウのサイズを大きくします。
左上および右上では WrapPanel の列の数が増えています。
左下では Viewbox に合わせてコンテンツが拡大されるのに対し、右下では Viewbox が一定以上は大きくなりません。

大きくした状態

 

作成したサンプル
LayoutWpf (GitHub)

参照
Grid クラス
ScrollViewer クラス
Viewbox クラス

ウィンドウ枠のない WPF アプリを作成する

WPF アプリケーションを普通に作成すると、Windows 標準のウィンドウ枠が付いてきます。
また、このウィンドウ枠のある状態では、他のアプリケーションをまたいだ透明効果を有効にすることができません。

まず、ウィンドウ枠を消すには、Window.WindowStyle プロパティに None を設定します。
また、透明効果を付けるには Window.AllowsTransparency プロパティに True を設定するのですが、
そのためにはウィンドウ枠を消すことが必須です。
ちなみに Blend では、AllowsTransparency に True を設定すると、自動的に WindowStyle に None が設定されます。

<Window x:Class="BorderlessWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml&quot;
Title="MainWindow" Height="200" Width="200" AllowsTransparency="True" WindowStyle="None" Background="{x:Null}">
<Grid>
<Ellipse Fill="#993399FF" Height="100" Width="100"/>
</Grid>
</Window>
view raw MainWindow.xaml hosted with ❤ by GitHub
using System.Windows;
namespace BorderlessWpf
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MouseLeftButtonDown += (o, e) => DragMove();
}
}
}

(全体のソースコードは GitHub の BorderlessWpf にあります。)

このサンプルでは、Window.Background に null を設定しています。
Background="Transparent" としてもよいでしょう。
また、中央には透明度のある円を配置しています。

これを実行すると、図のように、下層にあるアプリケーションまで透過して見えるようになります。
円の周囲の完全に透明な領域では、マウスやタッチなどの入力が透過し、下層にあるアプリケーションにヒットします。

BorderlessWpf

 

しかし、ウィンドウ枠がなくなると、マウスのドラッグによりアプリケーションを移動できなくなってしまいます。
そこで、Window の MouseLeftButtonDown イベントで DragMove メソッドを実行することにより、
ウィンドウ全体をドラッグで移動できるようになります。

作成したサンプル
BorderlessWpf (GitHub)

参照
Window.AllowsTransparency プロパティ
Window.DragMove メソッド

カテゴリー: クライアント技術. タグ: . Leave a Comment »