What’s New in Mathematica 12

ウルフラムリサーチアジアリミティッド
金光 安芸子

Join the Conversation @WolframJapan

What’s New in Mathematica 12

今年30周年を迎えたMathematicaは，バージョン１からずっとコードの互換性が維持されてきた．
Mathematica12 では，新しい関数が追加されるだけでなく，インターフェイスや他のプログラミング言語との相互運用性の向上，コアな言語の効率化など様々な改良もされている．今回は，OverViewとして以下の機能について紹介する．(リリース前のため，ベータ版でデモを行います）

このファイルは、Mathematica バージョン12 β版で実行しています。ほとんどの機能が、バージョン12の新機能です。V11.3以前のMathematicaでは機能しません。バージョン12のリリースをお待ちください。

最適化の新しい機能

幾何学の新しい機能

可視化の新しい機能

ニューラルネットワーク ~VAE , GAN~

非線形偏微分方程式への有限要素法の適用(13:00-13:30 丸山)

その他の新機能

最適化の新しい機能

Mathematica12 では以下が追加される（予定）

凸最適化の新しいソルバー

LinearOptimization — minimize {c.x|a.x+b \[VectorGreaterEqual]0}

LinearFractionalOptimization — minimize {(α.x+β)/(γ.x+δ|a.x+b\[VectorGreaterEqual]0}

QuadraticOptimization — minimize {(1/2)x.q.x+c.x|a.x+b\[VectorGreaterEqual]0}

SecondOrderConeOptimization — minimize {c.x|‖(Subscript[a, j]).x+(Subscript[b, j])‖≤(Subscript[α, j])+(Subscript[β, j]),j=1… k}

SemidefiniteOptimization — minimize {c.x|(Subscript[a, 0])+(Subscript[x, 1])(Subscript[a, 1])+…+(Subscript[x, k])(Subscript[a, k])(Subscript[\[VectorGreaterEqual], (Subscript[𝒮, +]^n)])0}

ConicOptimization — minimize {c.x|(Subscript[a, j]).x+(Subscript[b, j])(Subscript[\[VectorGreaterEqual], (Subscript[κ, j])])0, j=1… k}

一般的な最適化のソルバー

FindMinimum — 数値的に局所的制約条件付きの最適化問題を解く

NMinimize — 数値的に大域的制約条件付きの最適化問題を解く

フィッティング

FitRegularization —  Fit , FindFit のオプション

モデリングツール

ベクトル不等式

パラメータ”制約”不等式

効率の良い標準形への変形

新しい最適化機能の例

Linear Optimization: ロバストフィット

||a.λ-b(Subscript[||, 1])を最小化することによって，非線形離散データのロバストフィットを求める.

外れ値を持つノイズ入りデータを生成する．

data=;
dataPlot = ListPlot[data, PlotRange->All]

基底関数 (Subscript[ϕ, i])(x)=(((1+(((x-(Subscript[c, i])))^2)))^(1/2))を使って，データをフィットする．近似モデルは s(x)=(∑_(i=1))(Subscript[λ, i])(Subscript[ϕ, i])(x)である．

bases = Sqrt[1+(x-#)^2]&/@Subdivide[-3,3,10];
input=DesignMatrix[data,bases,x,IncludeConstantBasis->False];
output=data[[All,2]];

LinearOptimizationで近似関数の係数を求める．

res=LinearOptimization[Total[s],{a==input,b==output,-s\[VectorLessEqual]a.λ-b\[VectorLessEqual]s}, {λ,s}];
Short[res,10]

フィットを可視化する．

Show[dataPlot,Plot[Evaluate[bases.λ/.res],{x,-3,3},PlotStyle->Red]]

近似モデルを参照関数および最小二乗フィットと比較する．

lsqfit=Fit[data,bases,x];Show[dataPlot,Plot[{Sin[2x]+Cos[x^2],Evaluate[bases.λ/.res],lsqfit},{x,-3,3}, PlotStyle->{Green,Red,Blue},PlotLegends->{"参照関数","(Subscript[L, 1])fit","最小二乗フィット"}]]

Linear Optimization: データの分類

平面上で2つの点集合を分離する直線を求める．

SeedRandom[1234];
set1=RandomReal[{0,1/2},{40,2}];
set2=RandomReal[{1/2,1},{60,2}];
dataPlot=ListPlot[{set1,set2},PlotMarkers->{Automatic, PointSize[0.025]}]

分割のため，set1 は  a.(Subscript[p, i])+b \[VectorGreaterEqual]1 を満たし，set2 は a.(Subscript[q, j])+b\[VectorLessEqual]-1　を満たすような a,b を求める：

res=LinearOptimization[
0,{set1.a+b\[VectorGreaterEqual]1,set2.a+b\[VectorLessEqual]-1},{a,b}]

直線の式は以下のようになる：

line=a.{x,y}+b /. res

Show[dataPlot,ContourPlot[line==0,{x,0,1},{y,0,1},ContourStyle->Red]]

Quadratic Optimization: 凸多面体の間の最短距離

２つの凸多面体の間の距離を求める：

SeedRandom[1234];
region1=ConvexHullMesh[RandomReal[1,{50,3}]];
region2=ConvexHullMesh[RandomReal[{1,2},{50,3}]];
Show[region1,region2]

{dist,minPts}=QuadraticOptimization[Norm[x1-x2]^2,{x1∈region1,x2∈region2},{x1,x2},{"PrimalMinimumValue", "PrimalMinimizerRules"}]

最も距離の近い２点と、それらを結ぶ直線を可視化:

Show[region1,region2,Graphics3D[{Green,Thick,Line[{x1,x2}],Red,PointSize[0.025],Point[{x1,x2}]} /. minPts]]

Optimization modeling：最小包囲楕円体

m 個の点の集合が与えられたとき，n次元の (Subscript[x, i]) は，すべての点を囲む最小体積楕円体であるLöwner-John楕円体を求める．

(ℝ^n) の楕円体は，‖A.x+b‖≤ 1 である点集合 x によって記述することができる．このとき A は n×n の半正定値行列，b は n ベクトルである．楕円体の体積はdet((A^(-1)))に比例する．log(det((A^(-1))))=-log(det(A))は凸であり，以下の解を見付ける．

解のアルゴリズムはより大きい次元 n を扱うことができるが，ここでは可視化ができるように三次元のランダムな点集合で行う．

n=3;
points=RandomReal[{-1,1},{47,3}];
Graphics3D[{PointSize[0.025],Point[points]},Axes->True]

NMinimizeに，ベクトル不等式で制約条件を指定し，最小値を求める．

{minval, rules}= NMinimize[{-Log[Det[a]],{a(Underscript[\[VectorGreaterEqual], (SemidefiniteConeString)])0, Table[Norm[a.xi+b]≤1,{xi,points}]}}, {a, b∈Vectors[n]}]

中心と重み行列を求め，体積が最小となる楕円体を求める．

ainv=Inverse[a/.rules];
center=-ainv.(b/.rules);
Σ=ainv.ainv;

３次元グラフィックスで描画：

Graphics3D[{PointSize[0.025],Point[points],Green,Opacity[.25],Ellipsoid[center,Σ]},Axes->True]

幾何学の新しい機能

角度の計算

PlanarAngle  ▪  DihedralAngle  ▪  SolidAngle

- ２辺のなす角　PlanarAngle[p->{(Subscript[q, 1]),(Subscript[q, 2])}]

({{, }, {"Counterclockwise"（反時計回り）, "Clockwise"（時計回り）}})   ({{, , }, {"Interior", "Exterior", "FullExterior"}})

デフォルトは反時計回り

PlanarAngle[{0,0}->{{1,0},{1,1}}]

PlanarAngle[{0,0}->{{1,0},{1,1}}, "Counterclockwise"]

PlanarAngle[{0,0}->{{1,0},{1,1}}, "Clockwise"]

値の定義されていないシンボルでも使用することができる

PlanarAngle[{0,0}->{{1,0},{1,a}}]

内角，外角を指定する

PlanarAngle[{{0,0},{1,0},{1,1}}, "Interior"]

PlanarAngle[{{0,0},{1,0},{1,1}}, "Exterior"]

PlanarAngle[{{0,0},{1,0},{1,1}}, "FullExterior"]

- ２つの平面のなす角 DihedralAngle[{(Subscript[p, 1]),(Subscript[p, 2])},{v,w}]

DihedralAngle[{{0,0,0},{0,1,0}},{{1,0,1},{1,0,0}}]

Graphics3D[{HalfPlane[{{0,0,0},{0,1,0}},{0,1,1}],HalfPlane[{{0,0,0},{0,1,0}},{1,0,0}]},Axes->True]

DihedralAngle[HalfPlane[{{0,0,0},{0,1,0}},{0,1,1}],HalfPlane[{{0,0,0},{0,1,0}},{1,0,0}]]

- 点 p とベクトル {u,v,...}で張られた立体角 SolidAngle[p,{u,v,...}]

({{, }, {"2D", "3D"}})

SolidAngle[{0,0}, {{1,0}, {1,1}}]

SolidAngle[{0,0,0},{{1,0,1},{1,1,1},{0,0,1}}]

幾何学の新しい機能

Synthetic Geometry [Experimental]

座標を用いず，シンボリックに抽象的な指定だけで図形を作図する．また，作図された図形から推測できる結果を得ることができる．

GeometricScene  ▪  FindGeometricConjecture  ▪  GeometricAssertion  ▪  RandomInstance

TriangleConstruct  ▪  TriangleCenter  ▪  AngleBisector  ▪  Midpoint

GeometricSceneで，角Aが 30°の三角形ABCを表現し，(RefLink[RandomInstance, paclet:ref/RandomInstance]) で一つの例を作図する:

GeometricScene[{a,b,c},{Triangle[{a,b,c}],PlanarAngle[{a,b,c}]==30°}];
RandomInstance[%]

この時の点の座標を求めることができる：

%["Points"]

座標を指定して作図することもできる：

GeometricScene[{a->{0,0},b->{1,0},c->{0,1}},{Triangle[{a,b,c}]}]

FindGeometricConjecturesでConclusionsを指定すると，作図された図形から推測できる結果を返す：

FindGeometricConjectures[%]["Conclusions"]

定理の証明

円周上の異なる３点A, B, Cを取り，ACが直径の時，角 ∠ABC は直角になる。
（タレスの定理）

thalesHyp1 = GeometricScene[
{"A","B","C","O"},
{
CircleThrough[{"A","B","C"},"O"],
Triangle[{"A","B","C"}],
"O"==Midpoint[{"A","C"}]
}
];
thalesPic1=RandomInstance[thalesHyp1]

作図された図形から考えられる推論を返す．

FindGeometricConjectures[thalesPic1]["Conclusions"]

幾何学の新しい機能

多角形と多面体

Polygon

({{, , (Spacer1), , }})

Polygon[{{0.35, 0.2}, {0.9, 0.75}, {0.1, 0.55}, {0.9, 0.35}, {0.42, 0.9}}]

Region[%]

Polyhedron

({{, }})

Polyhedron[{{{1,0,0},{0,1,0},{0,0,1}},{{0,1,0},{1,0,0},{0,0,0}},{{0,0,1},{0,0,0},{1,0,0}},{{0,0,0},{0,0,1},{0,1,0}}}]

Graphics3D[%]

可視化の新しい機能

複素関数の可視化

ReImPlot, AbsArgPlot, ComplexPlot, ComplexPlot3D, ComplexListPlot

ReImPlotを使って，実変数の複素関数の実部と虚部をプロットする．実部は実線，虚部は点線で描画する．

ReImPlot[JacobiZeta[x,10],{x,-2Pi,2Pi},Ticks->{Range[-2Pi,2Pi,Pi/2],Automatic},PlotLegends->Automatic,PlotTheme->"Web"]

AbsArgPlotを使って，実変数の複素関数の絶対値Absをプロットし，偏角Argを示すためにグラフを色付けする．

AbsArgPlot[ArcSin[(Sqrt[x])-I Sin[4x]],{x,-π,π},PlotLegends->Automatic,PlotTheme->"Web"]

ComplexPlotでは凡例に示されているように，絶対値が大きいほど明るさが減少する．色は複素平面上の点における関数値の引数に対応する．

ComplexPlot[(((z^2)+1)/((z^2)-1)),{z,-3-2I,3+2I},PlotLegends->Automatic]

Log[Abs[f]] とArg[f] の両方に基づいて，周期的に陰影を付ける．

ComplexPlot[((Gamma[z-1])/((Gamma[z+I])^2)),{z,-3.5-2I,3.5+2I},ColorFunction->"CyclicLogAbsArg",PlotLegends->Automatic]

ラプラス変換の３次元可視化

lt=LaplaceTransform[(t^2) SawtoothWave[t/2],t,s]//Apart

ComplexPlot3D[Evaluate[lt],{s,-10-15I,20+15I},ScalingFunctions->"Log",PlotLegends->Automatic]

可視化の新しい機能

地理情報の可視化

GeoVectorPlot, GeoStreamPlot

例：北極における地球の磁気をストリームラインで可視化する.

北極近辺の地理情報を得る：

coords=GeoPosition[Flatten[Table[{lat,lon},{lat,80,90,10},{lon,-180,180,10}],1]];

GeoGraphics[{GeoStyling[Opacity[.2]],Red,Polygon[coords],Red,PointSize[Large],Point[GeoPosition["NorthPole"]]},GeoGridLines->Quantity[10,"AngularDegrees"],GeoCenter->GeoPosition["NorthPole"],GeoRange->"World",GeoProjection->"LambertAzimuthal"
]

磁場データを取得する：

gm=GeomagneticModelData[coords];

磁場の成分を抽出，可視化する：

norms=QuantityMagnitude[gm[[All,"Magnitude"]]];
declinations=gm[[All,"Declination"]];
vectors=Transpose[{norms,declinations}];
GeoStreamPlot[GeoVector[coords->vectors],GeoBackground->"ReliefMap",StreamStyle->White]

可視化の新しい機能

コンピュータビジョン

ImageContents,ImageCases,ImageBoundingBoxes

機械学習の機能と知識データベースを元に，画像に写っている複数のものを識別し，その情報を得る：

ImageContents[]

写っているものを識別し，連想を求める．

ImageCases[]

画像の中から，鳥を見つけ，認識された境界ボックスをハイライトする

ImageBoundingBoxes[i=,(Entity["bird", Entity["Concept","Bird::56ny3"], "Entity[\"Concept\", \"Bird::56ny3\"]", "concept"])]

HighlightImage[i,%,{"Lighten",0.5}]

ニューラルネットワーク~VAE,GAN~

Wolframは他に先駆けて高度に自動化された機械学習を開発し，これをWolfram言語に強固に統合してきた．その結果，専門家ではなくても，広範な分野における最新の機械学習が使えるようになっている．
また，従来の機械学習メソッドだけでなく最新のニューラルネットやディープラーニングもサポートしている．

- Classifiers（分類器）

- Generators（生成器）

- Auto-Encoders（オートエンコーダ）

- 変分自己符号化器 (VAE)

- 敵対的生成ネットワーク (GAN)

- Wasserstein GANs

- Cyclic GANs

- MNISTデータ集合を使用する(Wolfram Data Repository)

MNIST データを読み込む：

resource=ResourceObject[];

trainMNIST=RandomSample@ResourceData[resource,"TrainingData"];

testMNIST=RandomSample@ResourceData[resource,"TestData"];

avgDigits={,,,,,,,,,};

Classifiers（分類器）

Graphics[{
Opacity[1],FaceForm[Orange],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{12,0},.6],{i,1},{j,1,7}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{12,0},{i2,j2}+{15,0}}],{i1,1},{j1,1,7},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Lighter@Red],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{15,0},.6],{i,1},{j,2.5,5.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{15,0},{i2,j2}+{18,0}}],{i1,1},{j1,2.5,5.5},{i2,1},{j2,3.5,4.5}],

Opacity[1],FaceForm[Lighter@Blue],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{18,0},.6],{i,1},{j,3.5,4.5}]
},ImageSize->280
]

5

MINSTトレーニングデータを使って，手書き数字の画像を数字に分類するネットワークをトレーニングする．

ネットワークを構築する：

classifier=
NetChain[
{ConvolutionLayer[16,6,"Stride"->2],ElementwiseLayer[Ramp],
ConvolutionLayer[32,6,"Stride"->2],ElementwiseLayer[Ramp],
FlattenLayer[],
LinearLayer[256],ElementwiseLayer[Ramp],
LinearLayer[10],SoftmaxLayer[]},
"Input"->NetEncoder[{"Image",{28,28},"Grayscale","MeanImage"->0.5}],
"Output"->NetDecoder[{"Class",Range[0,9]}]
]

ネットワークをトレーニングする(訓練過程を要約する結果のオブジェクトを生成する)：

result=NetTrain[
classifier,
trainMNIST,
All,
ValidationSet->testMNIST
]

保存してある訓練済みネットオブジェクトを読み込む：

obtainNetTrainResults["classifier_net.wl", result]

オブジェクトから訓練済みネットを得る:

trainedclassifier=result["TrainedNet"]

訓練済みネットをテストデータで評価し，分類を行う：

Map[(#-> trainedclassifier[#])&,Keys@RandomSample[testMNIST,10]]

損失曲線

result["LossEvolutionPlot"]

分類子の確度を測る：

cm=ClassifierMeasurements[trainedclassifier,testMNIST];
cm["Accuracy"]

混同行列を可視化する

cm["ConfusionMatrixPlot"]

Generators（生成器）

Graphics[{
Opacity[1],FaceForm[Lighter@Blue],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{18,0},.6],{i,1},{j,3.5,4.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{18,0},{i2,j2}+{21,0}}],{i1,1},{j1,3.5,4.5},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Cyan],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{21,0},.6],{i,1},{j,2.5,5.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i2,j2}+{21,0},{i1,j1}+{24,0}}],{i1,1},{j1,1,7},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Green],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{24,0},.6],{i,1},{j,1,7}]
},ImageSize->280
]

5

数字から手書き数字の画像を生成するネットワークをトレーニングする．

generator を作成：

generator=
NetChain[
{UnitVectorLayer[10],
LinearLayer[256],ElementwiseLayer[Ramp],
LinearLayer[512],ElementwiseLayer[Ramp],
ReshapeLayer[{32,4,4}],
DeconvolutionLayer[16,6,"Stride"->2],ElementwiseLayer[Ramp],
DeconvolutionLayer[1,6,"Stride"->2],ElementwiseLayer[LogisticSigmoid]},
"Input"->NetEncoder[{"Class",Range[0,9]}],
"Output"->NetDecoder[{"Image","Grayscale"}]
]

MINSTトレーニングデータの向きを逆にして，ネットワークをトレーニングする：

result=NetTrain[
generator,
Map[Reverse,trainMNIST],
All,
ValidationSet->Map[Reverse,testMNIST]
]

保存してある訓練済みネットオブジェクトを読み込む：

obtainNetTrainResults["generator_net.wl", result]

オブジェクトから訓練済みネットを得る:

trainedgenerator=result["TrainedNet"]

訓練済みネットで、0~9の数字から手書き数字の画像を生成する：

Map[(#-> trainedgenerator[#])&,Range[0,9]]

Auto-Encoder（オートエンコーダ）

Graphics[{
Opacity[1],FaceForm[Orange],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{12,0},.6],{i,1},{j,1,7}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{12,0},{i2,j2}+{15,0}}],{i1,1},{j1,1,7},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Lighter@Red],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{15,0},.6],{i,1},{j,2.5,5.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{15,0},{i2,j2}+{18,0}}],{i1,1},{j1,2.5,5.5},{i2,1},{j2,3.5,4.5}],

Opacity[1],FaceForm[Lighter@Blue],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{18,0},.6],{i,1},{j,3.5,4.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{18,0},{i2,j2}+{21,0}}],{i1,1},{j1,3.5,4.5},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Cyan],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{21,0},.6],{i,1},{j,2.5,5.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i2,j2}+{21,0},{i1,j1}+{24,0}}],{i1,1},{j1,1,7},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Green],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{24,0},.6],{i,1},{j,1,7}]
},ImageSize->480
]

Auto-encoders(オートエンコーダ）は，入力をその出力にコピーするように学習させたニューラルネットワークである．
エンコーダで次元削減を行うと，小さい情報量の特徴表現を得ることができる．
入力データにランダムにノイズを加え，より意味のある特徴を抽出するDenoising AutoEncoderを行う．

画像を乱すためのノイズ関数を定義する：

noise[σ_]:=(img|->List@Clip[ImageData[img]+RandomReal[NormalDistribution[0,σ],ImageDimensions[img]],{0,1}])

ノイズを加えた画像はこのようになる：

Map[{#,Image[noise[0.5][#][[1]]]}&,avgDigits]//TableForm

オートエンコーダを構築する：

latentDim = 5;

autoEncoder= NetGraph[
<|
"encoder"->{
ConvolutionLayer[16,6,"Stride"->2],ElementwiseLayer[Ramp],
ConvolutionLayer[32,6,"Stride"->2],ElementwiseLayer[Ramp],
FlattenLayer[],
LinearLayer[256],BatchNormalizationLayer[],ElementwiseLayer[Ramp],
LinearLayer[latentDim]
},
"decoder"->{
LinearLayer[256],ElementwiseLayer[Ramp],
LinearLayer[512],ElementwiseLayer[Ramp],
ReshapeLayer[{32,4,4}],
DeconvolutionLayer[16,6,"Stride"->2],ElementwiseLayer[Ramp],
DeconvolutionLayer[1,6,"Stride"->2],ElementwiseLayer[LogisticSigmoid]
},
"loss"-> CrossEntropyLossLayer["Binary"]
|>,
{NetPort["NoisyInput"]-> "encoder"->"decoder"->NetPort["Output"],
"decoder"->NetPort["loss","Input"],
NetPort["Input"]->NetPort["loss","Target"]},
"Input"->NetEncoder[{"Image",{28,28},"Grayscale"}],
"NoisyInput"->NetEncoder[{"Function",noise[0.5],{1,28,28}}],
"Output"->NetDecoder[{"Image","Grayscale"}]
]

ノイズのある画像から生成した画像とクリーンな画像とを比較し、オートエンコーダを訓練する：

result=NetTrain[
autoEncoder,
<|"Input"->Keys[trainMNIST],"NoisyInput"->Keys[trainMNIST]|>,
All,
LossFunction->"Loss",
ValidationSet-><|"Input"->Keys[testMNIST],"NoisyInput"->Keys[testMNIST]|>,
MaxTrainingRounds->24
]

保存してある訓練済みネットオブジェクトを読み込む：

obtainNetTrainResults["auto-encoder_net.wl",result];

オブジェクトから訓練済みネットを得る:

AEnet = result["TrainedNet"]

うまく特徴を抽出することができたかを確認する．
訓練済みのAEネットワークから、エンコーダとデコーダをそれぞれ取り出す．

encoder=NetReplacePart[NetExtract[AEnet,"encoder"],"Input"->NetEncoder[{"Image",{28,28},"Grayscale"}]]

decoder=NetTake[AEnet,{"decoder",NetPort["Output"]}]

手書き数字を５次のベクトルにエンコードしてから，デコードする．

code=encoder[]

decoder[code]

ノイズ入りの画像からクリーンな画像を生成する関数 reconstructor を定義する：

reconstructor = decoder[encoder[#]]&;

テストデータからランダムな10個をサンプルとして reconstructorをテストする．

samples=Keys@RandomSample[testMNIST,10]

サンプル画像にノイズを加える．

noisy=Map[img|->ImageEffect[img,{"GaussianNoise",0.5}],samples]

reconstrustor にかけてノイズを除去する．

clean=Map[img|->reconstructor[img],noisy]

変分自己符号化器(VAE)

latentDims = 2;Graphics[{
Opacity[1],FaceForm[Orange],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{12,0},.6],{i,1},{j,1,7}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{12,0},{i2,j2}+{15,0}}],{i1,1},{j1,1,7},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Lighter@Red],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{15,0},.6],{i,1},{j,2.5,5.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{15,0},{i2,j2}+{18,0}}],{i1,1},{j1,2.5,5.5},{i2,1},{j2,3.5,4.5}],

Opacity[1],FaceForm[Lighter@Blue],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{18,0},.6],{i,1},{j,3.5,4.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{18,0},{i2,j2}+{21,0}}],{i1,1},{j1,3.5,4.5},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Cyan],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{21,0},.6],{i,1},{j,2.5,5.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i2,j2}+{21,0},{i1,j1}+{24,0}}],{i1,1},{j1,1,7},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Green],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{24,0},.6],{i,1},{j,1,7}],

Arrow[{{19,7.5},{19,5.5}}]
},ImageSize->480
]

Variational auto-encoders (VAEs)は、オートエンコーダの一つで、潜在変数での各データの分布がガウス分布になるようにしたもの．

latentDim = 2;
imageDims = {1,28,28};

Decoder:

decoder=NetChain[
{LinearLayer[2Times@@imageDims],
ReshapeLayer[imageDims {32,1/4,1/4}],
ElementwiseLayer[Ramp],
DeconvolutionLayer[16, 4, "Stride"->2,"PaddingSize"->1],
ElementwiseLayer[Ramp],
DeconvolutionLayer[1, 4, "Stride"->2,"PaddingSize"->1],
ElementwiseLayer[LogisticSigmoid]}
]

Encoder:

encoder=
NetGraph[
{ConvolutionLayer[16, 4, "Stride"->2, "PaddingSize"->1],
ElementwiseLayer[Ramp],
ConvolutionLayer[32, 4, "Stride"->2, "PaddingSize"->1],
ElementwiseLayer[Ramp],
FlattenLayer[],
LinearLayer[],
LinearLayer[]},
{NetPort["image"]->1-> 2->3->4->5,
5->6->NetPort["mean"],
5->7->NetPort["log_std"]}
]

潜在変数 z-Generator:

zGenerator=
NetGraph[
{ElementwiseLayer[Exp],ThreadingLayer[Times],TotalLayer[]},
{NetPort["log_std"]-> 1->2,
NetPort["random"]-> 2,
NetPort["mean"]-> 3,
2->3->NetPort["z"]}
]

Generation Loss:

generationLoss=MeanSquaredLossLayer[];

(* generationLoss=CrossEntropyLossLayer["Binary"]; *)

Latent Loss:

latentLoss=NetGraph[
{ThreadingLayer[{mean,logStD}|->(mean^2)+((Exp[logStD])^2)-2*logStD-1],
SummationLayer[],
ElementwiseLayer[sum|->sum/2]},
{{NetPort["mean"],NetPort["log_std"]}->1,
1->2->3->NetPort["latent_loss"]}
];

ネットワーク：

VAEnet = 
With[
{latentDim=latentDim},
NetGraph[
<|"encoder"->encoder,
"z_generator"->zGenerator,
"decoder"->decoder,
"generation_loss"->generationLoss,
"latent_loss"->latentLoss
|>,
{NetPort["Input"]->"encoder",
NetPort["encoder","mean"]-> NetPort["latent_loss","mean"],
NetPort["encoder","log_std"]-> NetPort["latent_loss","log_std"],
NetPort["encoder","mean"]-> NetPort["z_generator","mean"],
NetPort["encoder","log_std"]-> NetPort["z_generator","log_std"],
NetPort["Random"]-> NetPort["z_generator","random"],
"z_generator"->"decoder"-> NetPort["Output"],
NetPort["Input"]->NetPort["generation_loss","Target"],
"decoder"->NetPort["generation_loss","Input"],
"generation_loss"-> NetPort["generation_loss"]
},
"Input"->NetEncoder[{"Image", {28,28}, "Grayscale"}],
"Random"->NetEncoder[{"Function",RandomReal[NormalDistribution[],{latentDim}]&,{latentDim}}],
"Output"->NetDecoder[{"Image", "Grayscale"}]
]
]

トレーニングする．

trainingData =
<|"Input"->Keys@trainMNIST,"Random"->Table[1,{Length[trainMNIST]}]|>;

result = 
NetTrain[
VAEnet, 
trainingData, 
All,
LossFunction->{"latent_loss"->Scaled[1], "generation_loss"->Scaled[784]},
MaxTrainingRounds->100,
TrainingProgressReporting->"Panel",
Method->{"ADAM", "LearningRate"->0.0005},
 BatchSize->64
]

保存してある訓練済みネットオブジェクトを読み込む：

obtainNetTrainResults["vae_net.wl",result];

訓練済みネットを得る:

trainedVAE=result["TrainedNet"]

エンコーダとデコーダを取り出す

encoder=NetReplacePart[NetExtract[trainedVAE, "encoder"],"image"->NetEncoder[{"Image",Rest[imageDims],"Grayscale"}]];
decoder=NetReplacePart[NetExtract[trainedVAE, "decoder"],"Output"->NetDecoder["Image"]];

エンコーダに数字画像を入れ，得られたコードからデコーダで画像を生成する．

encoder[]

code="mean"/.encoder[]

decoder[code]

２次元のリストから作成した画像を２次元平面に描画する：

Graphics[
Flatten@Table[Inset[Image[decoder[{x,y}], ImageSize-> {28,28}],{x,y}],{x,-3,3,0.3},{y,-3,3,0.3}], Epilog->{EdgeForm[Red],FaceForm[Opacity[0.5],Red],Table[Tooltip[Disk["mean",Exp["log_std"]]/.encoder[avgDigits[[k]]],k-1],{k,1,10}]},
PlotRange->{{-3,3},{-3,3}},
ImageSize-> 640
]

２次元データから生成した数字画像をManipulateで滑らかに動かしてみる：

Manipulate[
Magnify[decoder[d],4],
{d,{-3,-3},{3,3}},SaveDefinitions->True
]

敵対的生成ネットワーク (GAN)

latentDims = 2;Graphics[{
Opacity[1],FaceForm[Lighter@Blue],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{12,0},.6],{i,1},{j,3.5,4.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{12,0},{i2,j2}+{15,0}}],{i1,1},{j1,3.5,4.5},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Cyan],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{15,0},.6],{i,1},{j,2.5,5.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i2,j2}+{15,0},{i1,j1}+{18,0}}],{i1,1},{j1,1,7},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Green],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{18,0},.6],{i,1},{j,1,7}],

Text["Generator",{16,0},Center],


Opacity[1],FaceForm[Orange],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{21,0},.6],{i,1},{j,1,7}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{21,0},{i2,j2}+{24,0}}],{i1,1},{j1,1,7},{i2,1},{j2,2.5,5.5}],

Opacity[1],FaceForm[Lighter@Red],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{24,0},.6],{i,1},{j,2.5,5.5}],

Black,Opacity[.5],AbsoluteThickness[2],
Table[Line[{{i1,j1}+{24,0},{i2,j2}+{27,0}}],{i1,1},{j1,2.5,5.5},{i2,1},{j2,4,4}],

Opacity[1],FaceForm[Lighter@Gray],EdgeForm[Black],
Reverse@Table[Disk[{i,j}+{27,0},.6],{i,1},{j,4,4}],

Text["Discriminator",{25,0},Center]
},ImageSize->480
]

敵対的生成ネットワーク（GAN）は、生成器(generator)が本物に似た画像を生成する. その敵対者である識別器（discriminator)は、訓練データの本物の画像と生成器が作った偽物の画像を識別しようとする.
ここでは，５次元のベクトルから画像を生成するGeneratorと，判別するdiscriminatorを作成し，学習させる．

latentDim = 5;
imageDims = {1,28,28};

Generator を構築:

generator=
NetChain[
{LinearLayer[256],ElementwiseLayer[Ramp],
LinearLayer[512],ElementwiseLayer[Ramp],
ReshapeLayer[{32,4,4}],
DeconvolutionLayer[16,6,"Stride"->2],ElementwiseLayer[Ramp],
DeconvolutionLayer[1,6,"Stride"->2],ElementwiseLayer[LogisticSigmoid]},
"Input"->latentDim
]

Discriminator を構築：

discriminator=
NetChain[
{ConvolutionLayer[16,6,"Stride"->2],ElementwiseLayer[Ramp],
ConvolutionLayer[32,6,"Stride"->2],ElementwiseLayer[Ramp],
FlattenLayer[],
LinearLayer[256],ElementwiseLayer[Ramp],
LinearLayer[1]},
"Input"->imageDims
]

Wasserstein GANを構築: (https://arxiv.org/abs/1701.07875)

wGAN=
NetGraph[
<|"generator"->generator,
"discriminator"->NetChain[{ReshapeLayer[Prepend[imageDims,2]],NetMapOperator[discriminator]}],
"combine"->CatenateLayer[],
"loss"->NetChain[{LinearLayer[1,"Weights"->{{-1,1}},"Biases"->{0}],PartLayer[1]},"Input"->{2,1}]|>,
{NetPort["Random"]->"generator"->"combine",
NetPort["Input"]->"combine",
"combine"->"discriminator"->"loss"},
"Input"->NetEncoder[{"Image",Rest@imageDims,"Grayscale"}],
"Random"->latentDim
]

GANをトレーニング:

trainingData=<|"Random"->RandomReal[{-1,1},{Length[trainMNIST],latentDim}],"Input"->Keys@trainMNIST|>;

result=
NetTrain[
wGAN,
trainingData,
All,
LossFunction->"Output",Method->{"ADAM","Beta1"->0.5,"LearningRate"->0.00005,"WeightClipping"->{"discriminator"->0.01}},
LearningRateMultipliers->{"loss"->0,"generator"->-0.2},BatchSize->64,
MaxTrainingRounds->1000
]

obtainNetTrainResults["MNIST_GAN.wl",result]

結果から訓練済みのネットを得る:

wGAN = result["TrainedNet"]

GAN generator を取り出し，ランダムな５次元のベクトルから，画像を生成してみる．

wGANgenerator=NetExtract[wGAN,"generator"]

Table[Image[First[wGANgenerator[RandomReal[{-1,1},{5}]]]],{k,1,10}]

CycleGAN

ペアになっていない２つのデータセットを学習させ，写真から絵画を生成したり，ウマの写真をシマウマに変換したりできるCycleGANを紹介する．

Source: “Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks” by Jun-Yan Zhu, Taesung Park, Phillip Isol, Alexei A. Efros.

モネの絵を写真に変換するCycleGAN：

Wolfram Neural Net Repository　からトレーニングされたネットワークを使う

net=NetModel["CycleGAN Monet-to-Photo Translation"]

モネの絵画を取り込む:

img=;

期待する次元で新しいエンコーダを作成する:

netEnc=NetEncoder[{"Image",ImageDimensions[img]}]

作成したエンコーダを追加してネットワークを作る:

resizedNet=NetReplacePart[net,{"Input"->netEnc,"Output"->NetDecoder[{"Image"}]}]

img2=resizedNet[img]

逆に，写真をモネの絵画風にするCycleGAN:

net2=NetModel["CycleGAN Photo-to-Monet Translation"]

期待する次元で新しいエンコーダを作成する:

netEnc2=NetEncoder[{"Image",ImageDimensions[img2]}]

作成したエンコーダを追加してネットワークを作る:

resizedNet2=NetReplacePart[net2,{"Input"->netEnc2,"Output"->NetDecoder[{"Image"}]}]

resizedNet2[img2]

その他の新しい情報

Molecular Structure & Computation(分子構造と計算）

m = Molecule["O=C(C1CCC1)S[C@@H]1CCC1(C)C"];
Show[GraphicsGrid[{{MoleculePlot[m],MoleculePlot3D[m,{Bond[{"C","O"}],Atom["C","RingMemberQ"->True]}],MoleculePlot3D[m,{Bond[{"C","S"}]}]}}]]

Microcontroller Kit （マイクロコントローラーキット）

(RefLinkPlain[Sample Projects, paclet:MicrocontrollerKit/workflowguide/MicrocontrollerKitWorkflowGuide]) — explore step-by-step workflows of sample projects

Unity Game Engine Interface（Unityゲームエンジンのインターフェイス）

(RefLinkPlain[Getting Started, paclet:UnityLink/workflowguide/GettingStarted]) — learn how to use UnityLink

(RefLinkPlain[Sample Projects, paclet:UnityLink/guide/SampleProjects]) — explore game-ready examples

Free to play, to manipulate  both on the cloud and desktop

ドキュメントを作り，簡単にクラウドに公開でき，誰でも動かすことができる．

Notebook Archive

インタラクティブで計算可能なノートブックを誰でも保存することができる．

Function Repository

https://resources.wolframcloud.com/FunctionRepository/

Wolfram Function Repositoryは，パブリックリソース．Wolfram Languageでの計算にすぐに使える，投稿された単独の関数群のコレクションを提供する．

Demonstration Project

http://demonstrations.wolfram.com/

ノートブックへのコピー＆ペーストが簡単に

toXY[z_]:={Re[z],Im[z]}
toZ[{x_,y_}]:=x+y I
arch[c_,s_,w_,n_,col_]:=Module[{Δ,k,u=π/3.0,c1},
Δ=u/20;
c1=toZ[c];
{EdgeForm[Thick],Lighter[col],Polygon[toXY/@(c1+Join[s(2(E^(1.Range[0,u,Δ] I))-1),s(2(E^(1.Range[2u,π,Δ] I))+1),{w-s},(s-w)(2(E^(1.Range[π,2u,-Δ] I))+1),(s-w)(2(E^(1.Range[u,0,-Δ] I))-1)])],col,Thick,Circle[c+{s-w/3,0},2(s-w/3),{2u,π}],Circle[c+{-s+w/3,0},2(s-w/3),{0,u}],Thin,Circle[c+{s-0.9 w,0},2(s-0.9w),{2u,π}],Circle[c+{-s+0.9 w,0},2(s-0.9 w),{0,u}],Darker[col],Thick,Table[Line[toXY/@{c1-s+2s (E^(u k I/n)),c1-s+w+2(s-w) (E^(u k I/n))}],{k,n}],Table[Line[toXY/@{c1+s+2s (E^((π-u k/n) I)),c1+s-w+2(s-w) (E^((π-u k/n)I))}],{k,n}]}]

circle[c_,s_,w_,n_,col_]:=Module[{Δ=π/60.,k,c1},
c1=toZ[c];
{EdgeForm[Thick],Lighter[col],Polygon[toXY/@ Join[c1+s (E^(Range[0,2π,Δ]I)),{c1+s-w},c1+(s-w) (E^(Range[2π,0,-Δ]I))]],col,Thick,Circle[c,s-w/3],Thin,Circle[c,s-0.9w],Darker[col],Thick,Table[Line[toXY/@{c1+s (E^(2π k I/n)),c1+(s-w) (E^(2π k I/n))}],{k,n}]}]

Manipulate[
r=.75;
c1=RGBColor[0.14,0.5,0.6];
c2=RGBColor[0.42,0.3,0.2];
c3=RGBColor[0.6,0.64,0.45];
{{a,b}}=({aa,bb}/.NSolve[{aa+2bb==r,Sin[π/n]==bb/(aa+bb)},{aa,bb}]);
Graphics[{arch[{0,0},1,w1,3,c1],circle[{0,r},r,w2,20,c2],Table[circle[toXY[r I+(a+b)(E^((2π k/n+t) I))],b,w3,10,c3],{k,n}],circle[{0,r},a,w3/2,10,c3]},ImageSize->{500,380}],
{{n,5,"number of small circles"},Range[3,10],SetterBar},
{{w1,0.1,"width of blue arch"},0,0.3},
{{w2,0.07,"width of brown circle"},0,0.2},
{{w3,0.03,"width of gray circles"},0,0.1},
{{t,0,"rotate"},0,2π},SaveDefinitions->True,TrackedSymbols->True]

ご静聴ありがとうございました

Mathematica 12 日本語版のリリースを楽しみにお待ちください．

Initializations

Save and ObtainNetTrainResults

SetAttributes[obtainNetTrainResults,HoldRest];

obtainNetTrainResults[file_String,result_NetTrainResultsObject]:=
If[
Not@FileExistsQ[FileNameJoin[{NotebookDirectory[],file}]],
Put[result,FileNameJoin[{NotebookDirectory[],file}]]
];

obtainNetTrainResults[file_String,result:(_NetChain|_NetGraph)]:=
If[
Not@FileExistsQ[FileNameJoin[{NotebookDirectory[],file}]],
Export[FileNameJoin[{NotebookDirectory[],file}],result]
];

obtainNetTrainResults[file_String,result_Symbol]:=
If[
FileExistsQ[FileNameJoin[{NotebookDirectory[],file}]],
result=Import[FileNameJoin[{NotebookDirectory[],file}]],
$Failed
];