{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "![MOSEK ApS](https://www.mosek.com/static/images/branding/webgraphmoseklogocolor.png )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Regularized Wasserstein Barycenters using Mosek and the exponential cone" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In a [previous notebook related to Wasserstein distances](https://nbviewer.jupyter.org/github/MOSEK/Tutorials/blob/master/wasserstein/wasserstein-bary.ipynb) we defined the linear optimization problem of computing the Wasserstein barycenter of a set of discrete measures. Here we solve an entropy-regularized variant of the same problem and to demonstrate the exponential cone capabilities of MOSEK. We also use this problem to compare Fusion and CVXPY." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a reminder, the $p$-th order Wasserstein distance $W_p(\\mu,\\upsilon)$ between discrete probability distributions $\\mu,\\upsilon$ is the objective value of the following problem:\n", "
\n", "
\n", "$$ \\mbox{minimize} \\quad \\sum_{i=1}\\sum_{j=1} D(X_i,Y_j)^p\\pi_{ij}$$\n", "
\n", "$$ \\mbox{st.} \\quad \\sum_{j=1} \\pi_{ij} = \\mu_i , \\quad i = 1,2,..n $$\n", "
\n", "$$ \\quad \\sum_{i=1} \\pi_{ij} = \\upsilon_j, \\quad j = 1,2,..m $$\n", "
\n", "$$ \\pi_{ij} \\geq 0, \\quad \\forall_{i,j}$$\n", "
\n", "where $D(X_i,Y_j)$ is the distance function.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Wasserstein Barycenter with regularization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The entropy regularized barycenter problem with $p=2$ is:\n", "
\n", "$$ \\mbox{minimize} \\quad \\frac1N \\sum_{i,j,k}^{N} D(X_i,Y_j)^2\\pi_{ij}^k + \\frac1\\lambda\\sum_{i,j,k} \\pi_{ij}^k\\log(\\pi_{ij}^k)$$\n", "
\n", "$$\\mbox{st.} \\quad \\sum_{j=1} \\pi_{ij}^{k} = \\mu_i, \\quad \\forall_{k,i} \\quad (1)$$\n", "
\n", "$$ \\quad \\sum_{i=1} \\pi_{ij}^{k} = \\upsilon_j^{k}, \\quad \\forall_{k,j} \\quad (2) $$\n", "
\n", "$$ \\pi_{ij}^{k} \\geq 0 \\quad \\forall_{k,i,j}$$\n", "
\n", "where $D(X_i,Y_j)$ is the euclidian distance between pixels, $\\lambda = median(D(X_i,Y_j))$ and $N$ is the number of samples.\n", "\n", "Without the entropy term the problem is just the linear problem of computing a distribution $\\mu$ minimizing the sum of distances to $\\upsilon_i$, as studied in our other notebook. Entropy regularization was suggested to us by Stefano Gualandi and appears for example in the paper by Cuturi and Doucet http://proceedings.mlr.press/v32/cuturi14.pdf. This paper contains also more details about the choice of $\\lambda$. Also more detailed information about LP aproach to Wasserstein metric can be found in [Stefano Gualandi's blogpost](http://stegua.github.io/blog/2018/12/31/wasserstein-distances-an-operations-research-perspective/).\n", "\n", "In this problem, Wasserstein Barycenter of Three's are visualized using images with size $28x28$ using $2$ handwriten '3' digits from MNIST database. Computations are carried out by Intel(R) Xeon(R) CPU E5-2687W v4 @ 3.00GHz processor." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "scrolled": false }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "import struct\n", "import numpy as np\n", "import pandas as pd\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "#Define the number of images for the barycenter calculation\n", "n=2\n", "number = 3\n", "\n", "#Read the images from the file\n", "def read_idx(filename):\n", " with open(filename, 'rb') as f:\n", " zero, data_type, dims = struct.unpack('>HBB', f.read(4))\n", " shape = tuple(struct.unpack('>I', f.read(4))[0] for d in range(dims))\n", " return np.frombuffer(f.read(), dtype=np.uint8).reshape(shape)\n", " \n", "data = read_idx('train-images.idx3-ubyte')\n", "labels = read_idx('train-labels.idx1-ubyte')\n", "#Select the images\n", "digits = data[labels == number]\n", "train = digits[:n]\n", "\n", "plt.figure(figsize=(20,10))\n", "for i in range(10):\n", " plt.subplot(2,5,i+1)\n", " plt.imshow(digits[np.random.randint(0,digits.shape[0])])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Regularized Barycenters using Mosek Fusion" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "from mosek.fusion import *\n", "import time\n", "import sys\n", "\n", "class Wasserstein_Fusion:\n", " \n", " def __init__(self):\n", " self.time = 0.0\n", " self.M = Model('Wasserstein')\n", " self.result = None\n", " \n", " \n", " def single_pmf(self, data = None, img=False):\n", " \n", " ''' Takes a image or array of images and extracts the probabilty mass function'''\n", " \n", " if not img:\n", " v=[]\n", " for image in data:\n", " arr = np.asarray(image).ravel(order='K')\n", " v.append(arr/np.sum(arr))\n", " else:\n", " v = np.asarray(data).ravel(order='K')\n", " v = v/np.sum(v)\n", " return v\n", " \n", " def ms_distance(self, m ,n, constant=False):\n", " \n", " ''' Squared Euclidean distance calculation between the pixels '''\n", " \n", " if constant:\n", " d = np.ones((m,m))\n", " else:\n", " d = np.empty((m,m))\n", " coor = []\n", " for i in range(n):\n", " for j in range(n):\n", " coor.append(np.array([i,j]))\n", " for i in range(m):\n", " for j in range(m):\n", " d[i][j] = np.linalg.norm(coor[i]-coor[j])**2\n", " return d\n", " \n", " def Wasserstein_Distance(self, bc ,data, img = False):\n", " \n", " ''' Calculation of wasserstein distance between a barycenter and an image by solving the minimization problem '''\n", " \n", " v = np.array(self.single_pmf(data, img))\n", " n = v.shape[0]\n", " d = self.ms_distance(n,data.shape[1])\n", " with Model('Wasserstein') as M:\n", " #Add variable\n", " pi = M.variable('pi',[n,n], Domain.greaterThan(0.0))\n", " \n", " #Add constraints\n", " M.constraint('c1' , Expr.sum(pi,0), Domain.equalsTo(v))\n", " M.constraint('c2' , Expr.sum(pi,1), Domain.equalsTo(bc))\n", " \n", " M.objective('Obj.' , ObjectiveSense.Minimize, Expr.dot(d, pi))\n", " \n", " M.solve()\n", " objective = M.primalObjValue()\n", " \n", " return objective\n", " \n", " def Wasserstein_BaryCenter(self,data):\n", " \n", " M = self.M\n", " start_time = time.time()\n", " k = data.shape[0]\n", " v = np.array(self.single_pmf(data))\n", " n = v.shape[1]\n", " d = self.ms_distance(n,data.shape[1])\n", " \n", " #Add variables \n", " mu = M.variable('Mu', n, Domain.greaterThan(0.0)) \n", " pi = (M.variable('Pi', [k,n,n] , Domain.greaterThan(0.0)))\n", " \n", " #Add constraints \n", " \n", " #Constraint (1)\n", " M.constraint('B', Expr.sub(Expr.sum(pi,1) , Var.repeat(mu,1,k).transpose()), Domain.equalsTo(0.0))\n", " #Constraint (2)\n", " M.constraint('C', Expr.sum(pi,2), Domain.equalsTo(v))\n", " \n", " M.objective('Obj' , ObjectiveSense.Minimize, Expr.sum(Expr.mul(Expr.mul(Expr.reshape(pi.asExpr(), k, n*n) , d.ravel()), 1/k)))\n", " \n", " M.setLogHandler(sys.stdout)\n", " M.solve()\n", " self.result = mu.level()\n", " M.selectedSolution(SolutionType.Interior)\n", " self.objective = M.primalObjValue()\n", " self.time = time.time() - start_time\n", " \n", " return mu.level()\n", " \n", " def Wasserstein_regBaryCenter(self,data, _lambda = None, relgap = None):\n", " \n", " M = self.M\n", " start_time = time.time()\n", " k = data.shape[0]\n", " v = np.array(self.single_pmf(data))\n", " n = v.shape[1]\n", " d = self.ms_distance(n,data.shape[1])\n", " \n", " if not _lambda:\n", " _lambda = 60/np.median(d.ravel())\n", " \n", " \n", " #Add variables \n", " mu = M.variable('Mu', n, Domain.greaterThan(0.0)) \n", " pi = (M.variable('Pi', [k,n,n] , Domain.greaterThan(0.0)))\n", " z = M.variable('z', [k,n*n]) #Artificial variable \n", " \n", " #Add constraints\n", " #Intermediate conic constraints in form z <= -pi log(pi) \n", " for i in range(1,k+1):\n", " M.constraint(Expr.hstack(Expr.constTerm(n*n, 1.0),\n", " Expr.reshape(pi.asExpr(), k*n*n).slice(0+(i-1)*n*n, n*n*i),\n", " Expr.reshape(z.asExpr(), k*n*n).slice(0+(i-1)*n*n, n*n*i)),\n", " Domain.inPExpCone())\n", " \n", " #Constraint (1)\n", " M.constraint('B', Expr.sub(Expr.sum(pi,1) , Var.repeat(mu,1,k).transpose()), Domain.equalsTo(0.0))\n", " #Constraint (2)\n", " M.constraint('C', Expr.sum(pi,2), Domain.equalsTo(v))\n", " \n", " \n", " M.objective('Obj' , ObjectiveSense.Minimize, Expr.sum(Expr.mul(Expr.add(Expr.mul(Expr.reshape(pi.asExpr(), k, n*n), d.ravel()),Expr.mul(Expr.sum(z,1),-1/_lambda)), 1/k)))\n", " \n", " #relgap is set in case of approximation\n", " if relgap:\n", " M.setSolverParam(\"intpntCoTolRelGap\", relgap)\n", " \n", " M.setLogHandler(sys.stdout)\n", " M.solve()\n", " self.result = mu.level()\n", " self.objective = M.primalObjValue()\n", " \n", " self.time = time.time() - start_time\n", " \n", " return self.result\n", " \n", " \n", " \n", " def reset(self):\n", " self.M = Model('Wasserstein')\n", " " ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 3691072 \n", " Cones : 1229312 \n", " Scalar variables : 6147345 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer started.\n", "Presolve started.\n", "Linear dependency checker started.\n", "Linear dependency checker terminated.\n", "Eliminator started.\n", "Freed constraints in eliminator : 0\n", "Eliminator terminated.\n", "Eliminator - tries : 1 time : 0.00 \n", "Lin. dep. - tries : 1 time : 0.79 \n", "Lin. dep. - number : 1 \n", "Presolve terminated. Time: 4.88 \n", "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 3691072 \n", " Cones : 1229312 \n", " Scalar variables : 6147345 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 24 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 1138\n", "Optimizer - Cones : 1229312\n", "Optimizer - Scalar variables : 3687936 conic : 3687936 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 1.28 dense det. time : 0.00 \n", "Factor - ML order time : 0.01 GP order time : 0.00 \n", "Factor - nonzeros before factor : 2.79e+05 after factor : 3.41e+05 \n", "Factor - dense dim. : 0 flops : 1.17e+08 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 6.3e+02 5.1e+02 2.4e+07 0.00e+00 2.213290906e+07 -1.586952925e+06 1.0e+00 10.10 \n", "1 2.2e+02 1.8e+02 1.4e+07 -9.87e-01 1.997448375e+07 -3.251324601e+06 3.5e-01 12.82 \n", "2 1.4e+02 1.1e+02 1.0e+07 -8.50e-01 1.706335861e+07 -4.132584878e+06 2.2e-01 15.44 \n", "3 8.6e+01 6.9e+01 6.1e+06 -5.35e-01 1.255537920e+07 -4.350508351e+06 1.4e-01 17.98 \n", "4 3.9e+01 3.1e+01 2.3e+06 -5.91e-02 6.634411697e+06 -3.290271335e+06 6.2e-02 20.60 \n", "5 1.6e+01 1.3e+01 6.8e+05 4.56e-01 3.047731323e+06 -1.738035830e+06 2.5e-02 23.20 \n", "6 9.2e+00 7.4e+00 3.2e+05 6.93e-01 1.871267186e+06 -1.107832915e+06 1.5e-02 25.98 \n", "7 3.8e+00 3.0e+00 9.0e+04 7.82e-01 8.077963925e+05 -5.102524925e+05 5.9e-03 28.62 \n", "8 1.0e+00 8.1e-01 1.4e+04 8.51e-01 2.027478294e+05 -1.783065556e+05 1.6e-03 31.46 \n", "9 4.2e-01 3.4e-01 4.0e+03 8.87e-01 8.245159686e+04 -8.499836533e+04 6.6e-04 34.22 \n", "10 1.2e-01 9.9e-02 6.9e+02 9.00e-01 2.254754497e+04 -2.962276989e+04 2.0e-04 36.82 \n", "11 3.6e-02 2.9e-02 1.2e+02 9.02e-01 5.918291547e+03 -1.024285722e+04 5.7e-05 39.36 \n", "12 1.1e-02 8.5e-03 2.0e+01 9.00e-01 1.600474776e+03 -3.421335906e+03 1.7e-05 41.97 \n", "13 3.3e-03 2.6e-03 3.7e+00 9.03e-01 4.338461931e+02 -1.203269461e+03 5.2e-06 44.63 \n", "14 9.2e-04 7.4e-04 5.9e-01 9.15e-01 9.098495781e+01 -3.977520685e+02 1.5e-06 47.24 \n", "15 2.5e-04 2.0e-04 8.5e-02 9.22e-01 1.259274659e+00 -1.351784897e+02 3.9e-07 49.97 \n", "16 7.1e-05 5.7e-05 1.4e-02 9.31e-01 -1.815269221e+01 -5.892007163e+01 1.1e-07 52.66 \n", "17 1.6e-05 1.3e-05 1.6e-03 9.35e-01 -2.349890101e+01 -3.326483992e+01 2.6e-08 55.32 \n", "18 3.2e-06 2.6e-06 1.5e-04 9.38e-01 -2.441819572e+01 -2.642396208e+01 5.1e-09 57.91 \n", "19 7.5e-07 6.0e-07 1.7e-05 9.44e-01 -2.452957265e+01 -2.501505945e+01 1.2e-09 60.52 \n", "20 1.8e-07 1.4e-07 2.0e-06 9.49e-01 -2.454254575e+01 -2.466072167e+01 2.8e-10 63.35 \n", "21 3.6e-08 2.9e-08 1.9e-07 9.48e-01 -2.454079867e+01 -2.456580997e+01 5.7e-11 65.94 \n", "22 9.3e-09 7.5e-09 2.6e-08 9.50e-01 -2.453852251e+01 -2.454516650e+01 1.5e-11 68.59 \n", "23 2.3e-09 1.8e-09 3.3e-09 9.51e-01 -2.453774803e+01 -2.453943434e+01 3.6e-12 71.15 \n", "24 7.2e-10 5.0e-10 4.7e-10 9.51e-01 -2.453754481e+01 -2.453801359e+01 9.8e-13 73.75 \n", "25 7.1e-10 4.1e-10 3.6e-10 9.54e-01 -2.453752642e+01 -2.453791941e+01 8.1e-13 81.43 \n", "26 3.5e-10 9.8e-11 4.3e-11 9.54e-01 -2.453745494e+01 -2.453755111e+01 1.9e-13 88.92 \n", "27 7.1e-10 9.8e-11 4.3e-11 9.78e-01 -2.453745493e+01 -2.453755104e+01 1.9e-13 98.60 \n", "28 7.4e-10 9.8e-11 4.3e-11 9.79e-01 -2.453745493e+01 -2.453755104e+01 1.9e-13 110.68\n", "29 8.4e-10 9.8e-11 4.3e-11 9.79e-01 -2.453745492e+01 -2.453755103e+01 1.9e-13 121.76\n", "30 1.1e-09 9.8e-11 4.3e-11 9.83e-01 -2.453745492e+01 -2.453755100e+01 1.9e-13 134.08\n", "31 1.1e-09 9.8e-11 4.3e-11 9.79e-01 -2.453745492e+01 -2.453755099e+01 1.9e-13 145.08\n", "32 1.1e-09 9.8e-11 4.3e-11 9.77e-01 -2.453745490e+01 -2.453755091e+01 1.9e-13 155.13\n", "33 1.4e-09 9.8e-11 4.3e-11 9.78e-01 -2.453745488e+01 -2.453755083e+01 1.9e-13 164.86\n", "34 1.4e-09 9.8e-11 4.3e-11 9.79e-01 -2.453745488e+01 -2.453755081e+01 1.9e-13 175.32\n", "35 1.4e-09 9.8e-11 4.3e-11 9.77e-01 -2.453745485e+01 -2.453755066e+01 1.9e-13 184.89\n", "36 1.4e-09 9.8e-11 4.3e-11 9.77e-01 -2.453745482e+01 -2.453755053e+01 1.9e-13 193.91\n", "37 1.4e-09 9.8e-11 4.3e-11 9.80e-01 -2.453745481e+01 -2.453755051e+01 1.9e-13 204.86\n", "38 1.4e-09 9.7e-11 4.3e-11 9.84e-01 -2.453745481e+01 -2.453755048e+01 1.9e-13 215.45\n", "39 1.4e-09 9.7e-11 4.3e-11 9.79e-01 -2.453745480e+01 -2.453755047e+01 1.9e-13 226.12\n", "40 1.4e-09 9.7e-11 4.3e-11 9.79e-01 -2.453745479e+01 -2.453755043e+01 1.9e-13 236.39\n", "41 1.4e-09 9.7e-11 4.3e-11 9.80e-01 -2.453745478e+01 -2.453755039e+01 1.9e-13 246.32\n", "42 1.4e-09 9.7e-11 4.3e-11 9.82e-01 -2.453745478e+01 -2.453755038e+01 1.9e-13 257.70\n", "43 1.4e-09 9.7e-11 4.3e-11 9.77e-01 -2.453745477e+01 -2.453755033e+01 1.9e-13 267.63\n", "44 1.4e-09 9.7e-11 4.3e-11 9.80e-01 -2.453745476e+01 -2.453755030e+01 1.9e-13 277.59\n", "45 1.4e-09 9.7e-11 4.3e-11 9.79e-01 -2.453745476e+01 -2.453755027e+01 1.9e-13 288.02\n", "46 1.4e-09 9.7e-11 4.3e-11 9.78e-01 -2.453745475e+01 -2.453755026e+01 1.9e-13 298.50\n", "47 1.4e-09 9.7e-11 4.2e-11 9.78e-01 -2.453745472e+01 -2.453755009e+01 1.9e-13 307.32\n", "48 1.4e-09 9.7e-11 4.2e-11 9.80e-01 -2.453745472e+01 -2.453755008e+01 1.9e-13 318.93\n", "49 1.4e-09 9.7e-11 4.2e-11 9.79e-01 -2.453745472e+01 -2.453755008e+01 1.9e-13 329.79\n", "50 1.4e-09 9.7e-11 4.2e-11 9.79e-01 -2.453745471e+01 -2.453755007e+01 1.9e-13 340.67\n", "51 1.4e-09 9.7e-11 4.2e-11 9.78e-01 -2.453745471e+01 -2.453755007e+01 1.9e-13 351.40\n", "52 1.4e-09 9.7e-11 4.2e-11 9.85e-01 -2.453745468e+01 -2.453754991e+01 1.9e-13 360.84\n", "53 1.4e-09 9.7e-11 4.2e-11 9.86e-01 -2.453745468e+01 -2.453754991e+01 1.9e-13 372.95\n", "54 7.9e-10 1.1e-11 1.7e-12 1.00e+00 -2.453743187e+01 -2.453744287e+01 2.1e-14 379.56\n", "55 1.2e-09 1.1e-11 1.7e-12 1.00e+00 -2.453743185e+01 -2.453744281e+01 2.1e-14 390.36\n", "56 1.2e-09 1.1e-11 1.6e-12 1.00e+00 -2.453743181e+01 -2.453744264e+01 2.1e-14 400.86\n", "57 1.4e-09 1.1e-11 1.6e-12 1.00e+00 -2.453743175e+01 -2.453744243e+01 2.0e-14 410.98\n", "58 1.4e-09 1.1e-11 1.6e-12 1.00e+00 -2.453743175e+01 -2.453744242e+01 2.0e-14 423.31\n", "59 1.4e-09 1.1e-11 1.6e-12 1.00e+00 -2.453743175e+01 -2.453744241e+01 2.0e-14 436.25\n", "60 1.4e-09 1.1e-11 1.6e-12 1.00e+00 -2.453743175e+01 -2.453744241e+01 2.0e-14 449.46\n", "61 6.7e-10 1.0e-12 4.6e-14 1.00e+00 -2.453742837e+01 -2.453742939e+01 1.8e-15 456.59\n", "62 6.3e-10 1.0e-12 4.6e-14 1.00e+00 -2.453742837e+01 -2.453742939e+01 1.8e-15 469.17\n", "63 8.4e-10 1.0e-12 4.6e-14 1.00e+00 -2.453742837e+01 -2.453742939e+01 1.8e-15 481.70\n", "64 1.0e-09 1.0e-12 4.6e-14 1.00e+00 -2.453742837e+01 -2.453742939e+01 1.8e-15 494.25\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "65 1.1e-09 1.0e-12 4.6e-14 1.00e+00 -2.453742837e+01 -2.453742939e+01 1.8e-15 506.36\n", "66 1.3e-09 1.0e-12 4.6e-14 1.00e+00 -2.453742837e+01 -2.453742939e+01 1.8e-15 519.57\n", "67 1.2e-09 1.0e-12 4.6e-14 1.00e+00 -2.453742837e+01 -2.453742939e+01 1.8e-15 531.70\n", "68 1.2e-09 1.0e-12 4.6e-14 1.00e+00 -2.453742837e+01 -2.453742939e+01 1.8e-15 544.16\n", "Optimizer terminated. Time: 558.63 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: -2.4537428373e+01 nrm: 1e+00 Viol. con: 1e-07 var: 0e+00 cones: 2e-12 \n", " Dual. obj: -2.4537429385e+01 nrm: 8e+02 Viol. con: 0e+00 var: 2e-11 cones: 0e+00 \n", "\n", "Time Spent to solve problem with Fusion: \n", " 592.5434217453003\n", "Time Spent in solver: \n", " 558.629515171051\n", "Objective: \n", " -24.53742837253434\n" ] } ], "source": [ "fusion_model = Wasserstein_Fusion()\n", "f_bc = fusion_model.Wasserstein_regBaryCenter(train)\n", "print('\\nTime Spent to solve problem with Fusion: \\n {0}'.format(fusion_model.time))\n", "print('Time Spent in solver: \\n {0}'.format(fusion_model.M.getSolverDoubleInfo(\"optimizerTime\")))\n", "print('Objective: \\n {0}'.format(fusion_model.objective))" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 3136 \n", " Cones : 0 \n", " Scalar variables : 1230097 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer started.\n", "Presolve started.\n", "Linear dependency checker started.\n", "Linear dependency checker terminated.\n", "Eliminator started.\n", "Freed constraints in eliminator : 0\n", "Eliminator terminated.\n", "Eliminator - tries : 1 time : 0.00 \n", "Lin. dep. - tries : 1 time : 0.03 \n", "Lin. dep. - number : 1 \n", "Presolve terminated. Time: 0.96 \n", "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : LO (linear optimization problem)\n", " Constraints : 3136 \n", " Cones : 0 \n", " Scalar variables : 1230097 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 24 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 1138\n", "Optimizer - Cones : 0\n", "Optimizer - Scalar variables : 278320 conic : 0 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 0.11 dense det. time : 0.00 \n", "Factor - ML order time : 0.01 GP order time : 0.00 \n", "Factor - nonzeros before factor : 2.79e+05 after factor : 3.41e+05 \n", "Factor - dense dim. : 0 flops : 1.15e+08 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 1.8e+04 1.2e+04 5.7e+08 0.00e+00 2.533143200e+07 0.000000000e+00 5.1e+02 1.25 \n", "1 1.8e+00 1.2e+00 5.8e+04 -1.00e+00 2.530057802e+07 -1.985024391e+04 5.2e-02 1.32 \n", "2 4.0e-03 2.6e-03 1.3e+02 -6.05e-01 6.809717409e+04 -3.693719644e+04 1.1e-04 1.42 \n", "3 1.1e-03 7.4e-04 3.7e+01 2.56e+02 1.601417700e+02 -1.716296687e+01 3.3e-05 1.54 \n", "4 5.7e-04 3.7e-04 1.8e+01 1.42e+00 7.400571125e+01 -6.338392658e+00 1.6e-05 1.66 \n", "5 7.5e-05 4.9e-05 2.4e+00 1.20e+00 9.664295656e+00 -2.705164314e-01 2.2e-06 1.77 \n", "6 2.1e-05 1.4e-05 6.8e-01 1.06e+00 3.422966212e+00 6.973656981e-01 6.1e-07 1.87 \n", "7 4.1e-06 1.8e-06 1.3e-01 1.02e+00 1.573043800e+00 1.067352406e+00 1.1e-07 1.95 \n", "8 8.6e-07 3.7e-07 2.6e-02 1.00e+00 1.225114421e+00 1.119539692e+00 2.4e-08 2.06 \n", "9 1.5e-07 6.3e-08 4.5e-03 1.00e+00 1.147377919e+00 1.129274252e+00 4.0e-09 2.15 \n", "10 6.3e-09 2.9e-09 1.9e-04 1.00e+00 1.131288555e+00 1.130509098e+00 1.7e-10 2.21 \n", "11 7.4e-13 3.7e-13 2.3e-08 1.00e+00 1.130528318e+00 1.130528226e+00 2.0e-14 2.27 \n", "12 2.2e-16 6.3e-14 1.5e-12 1.00e+00 1.130528228e+00 1.130528228e+00 2.0e-18 2.31 \n", "Basis identification started.\n", "Basis identification terminated. Time: 0.07\n", "Optimizer terminated. Time: 2.72 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 1.1305282283e+00 nrm: 1e+00 Viol. con: 9e-16 var: 0e+00 \n", " Dual. obj: 1.1305282283e+00 nrm: 8e+02 Viol. con: 0e+00 var: 2e-13 \n", "\n", "Basic solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: 1.1305282283e+00 nrm: 1e+00 Viol. con: 2e-17 var: 0e+00 \n", " Dual. obj: 1.1305282283e+00 nrm: 8e+02 Viol. con: 0e+00 var: 1e-11 \n", "\n", "Time Spent to solve non-regularized problem with Fusion: \n", " 8.922340393066406\n", "Time Spent in solver: \n", " 2.7243459224700928\n", "The average Wasserstein distance between digits and the barycenter: \n", " 1.1305282283356233\n" ] } ], "source": [ "nonReg_model = Wasserstein_Fusion()\n", "nonReg = nonReg_model.Wasserstein_BaryCenter(train)\n", "print('\\nTime Spent to solve non-regularized problem with Fusion: \\n {0}'.format(nonReg_model.time))\n", "print('Time Spent in solver: \\n {0}'.format(nonReg_model.M.getSolverDoubleInfo(\"optimizerTime\")))\n", "print('The average Wasserstein distance between digits and the barycenter: \\n {0}'.format(nonReg_model.objective))" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "scrolled": true }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(15,8))\n", "plt.subplot(1,3,1)\n", "plt.imshow(np.reshape(f_bc,(28,28)))\n", "plt.title('Regularized Barycenter')\n", "plt.subplot(1,3,2)\n", "plt.imshow(np.reshape(nonReg, (28,28)))\n", "plt.title('Non-Regularized Interior Point Barycenter')\n", "plt.imshow(np.reshape(nonReg, (28,28)))\n", "plt.subplot(1,3,3)\n", "plt.title('Non-Regularized Basic Point Barycenter')\n", "plt.imshow(np.reshape(nonReg_model.result, (28,28)))\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$\\quad$ The interiror point solution is different than the basic solution, however this is just a coincidence. The interior point solution gives the convex combination of the extreme points if there is infinetly many optimal solutions but this is not always the case in this problem." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$\\quad $ Solving the problem even for just 2 images takes a long time. However, when the output of the iterations are investigated the solver is spending most of the time in earning very little improvements. Since the regularization term is an artificial addition to the problem, it is sensible to test if the approximation with a little loss of accuracy effects the values and images significantly or not, by using \"intpntCoTolRelGap\" parameter. This parameter controls the relative gap termination tolerance of the conic optimizer.\n", "In the next problem the parameter is increased from 1.0e-7 to 1.0e-3 in order to terminate Mosek with a little bit less accuracy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Obtaining approximate values" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 3691072 \n", " Cones : 1229312 \n", " Scalar variables : 6147345 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer started.\n", "Presolve started.\n", "Linear dependency checker started.\n", "Linear dependency checker terminated.\n", "Eliminator started.\n", "Freed constraints in eliminator : 0\n", "Eliminator terminated.\n", "Eliminator - tries : 1 time : 0.00 \n", "Lin. dep. - tries : 1 time : 0.75 \n", "Lin. dep. - number : 1 \n", "Presolve terminated. Time: 4.73 \n", "Problem\n", " Name : Wasserstein \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 3691072 \n", " Cones : 1229312 \n", " Scalar variables : 6147345 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 24 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 1138\n", "Optimizer - Cones : 1229312\n", "Optimizer - Scalar variables : 3687936 conic : 3687936 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 1.34 dense det. time : 0.00 \n", "Factor - ML order time : 0.01 GP order time : 0.00 \n", "Factor - nonzeros before factor : 2.79e+05 after factor : 3.41e+05 \n", "Factor - dense dim. : 0 flops : 1.17e+08 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 6.3e+02 5.1e+02 2.4e+07 0.00e+00 2.213290906e+07 -1.586952925e+06 1.0e+00 9.79 \n", "1 2.2e+02 1.8e+02 1.4e+07 -9.87e-01 1.997448375e+07 -3.251324601e+06 3.5e-01 12.58 \n", "2 1.4e+02 1.1e+02 1.0e+07 -8.50e-01 1.706335861e+07 -4.132584878e+06 2.2e-01 15.35 \n", "3 8.6e+01 6.9e+01 6.1e+06 -5.35e-01 1.255537920e+07 -4.350508351e+06 1.4e-01 18.28 \n", "4 3.9e+01 3.1e+01 2.3e+06 -5.91e-02 6.634411697e+06 -3.290271335e+06 6.2e-02 20.98 \n", "5 1.6e+01 1.3e+01 6.8e+05 4.56e-01 3.047731323e+06 -1.738035830e+06 2.5e-02 23.66 \n", "6 9.2e+00 7.4e+00 3.2e+05 6.93e-01 1.871267186e+06 -1.107832915e+06 1.5e-02 26.15 \n", "7 3.8e+00 3.0e+00 9.0e+04 7.82e-01 8.077963925e+05 -5.102524925e+05 5.9e-03 28.85 \n", "8 1.0e+00 8.1e-01 1.4e+04 8.51e-01 2.027478294e+05 -1.783065556e+05 1.6e-03 31.64 \n", "9 4.2e-01 3.4e-01 4.0e+03 8.87e-01 8.245159686e+04 -8.499836533e+04 6.6e-04 34.18 \n", "10 1.2e-01 9.9e-02 6.9e+02 9.00e-01 2.254754497e+04 -2.962276989e+04 2.0e-04 36.94 \n", "11 3.6e-02 2.9e-02 1.2e+02 9.02e-01 5.918291547e+03 -1.024285722e+04 5.7e-05 39.48 \n", "12 1.1e-02 8.5e-03 2.0e+01 9.00e-01 1.600474776e+03 -3.421335906e+03 1.7e-05 42.19 \n", "13 3.3e-03 2.6e-03 3.7e+00 9.03e-01 4.338461931e+02 -1.203269461e+03 5.2e-06 44.90 \n", "14 9.2e-04 7.4e-04 5.9e-01 9.15e-01 9.098495781e+01 -3.977520685e+02 1.5e-06 47.40 \n", "15 2.5e-04 2.0e-04 8.5e-02 9.22e-01 1.259274659e+00 -1.351784897e+02 3.9e-07 49.96 \n", "16 7.1e-05 5.7e-05 1.4e-02 9.31e-01 -1.815269221e+01 -5.892007163e+01 1.1e-07 52.59 \n", "17 1.6e-05 1.3e-05 1.6e-03 9.35e-01 -2.349890101e+01 -3.326483992e+01 2.6e-08 55.25 \n", "18 3.2e-06 2.6e-06 1.5e-04 9.38e-01 -2.441819572e+01 -2.642396208e+01 5.1e-09 57.85 \n", "19 7.5e-07 6.0e-07 1.7e-05 9.44e-01 -2.452957265e+01 -2.501505945e+01 1.2e-09 60.41 \n", "20 1.8e-07 1.4e-07 2.0e-06 9.49e-01 -2.454254575e+01 -2.466072167e+01 2.8e-10 62.93 \n", "21 3.6e-08 2.9e-08 1.9e-07 9.48e-01 -2.454079867e+01 -2.456580997e+01 5.7e-11 65.49 \n", "22 9.3e-09 7.5e-09 2.6e-08 9.50e-01 -2.453852251e+01 -2.454516650e+01 1.5e-11 68.06 \n", "23 2.3e-09 1.8e-09 3.3e-09 9.51e-01 -2.453774803e+01 -2.453943434e+01 3.6e-12 70.63 \n", "24 7.2e-10 5.0e-10 4.7e-10 9.51e-01 -2.453754481e+01 -2.453801359e+01 9.8e-13 73.16 \n", "Optimizer terminated. Time: 75.21 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: -2.4537544810e+01 nrm: 1e+00 Viol. con: 1e-08 var: 0e+00 cones: 6e-12 \n", " Dual. obj: -2.4538013590e+01 nrm: 8e+02 Viol. con: 0e+00 var: 1e-08 cones: 0e+00 \n", "\n", "Time Spent to solve problem with Fusion: \n", " 109.92306613922119\n", "Time Spent in solver: \n", " 75.20934391021729\n", "Objective: \n", " -24.53754480969593\n" ] } ], "source": [ "fusion_model2 = Wasserstein_Fusion()\n", "f_bc2 = fusion_model2.Wasserstein_regBaryCenter(train, relgap = \"1.0e-3\")\n", "print('\\nTime Spent to solve problem with Fusion: \\n {0}'.format(fusion_model2.time))\n", "print('Time Spent in solver: \\n {0}'.format(fusion_model2.M.getSolverDoubleInfo(\"optimizerTime\")))\n", "print('Objective: \\n {0}'.format(fusion_model2.objective))" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(10,10))\n", "plt.subplot(1,2,1)\n", "fus_bc = np.reshape(f_bc,(28,28))\n", "plt.imshow(fus_bc)\n", "plt.title('Optimal Barycenter')\n", "plt.subplot(1,2,2)\n", "fus_bc2 = np.reshape(f_bc,(28,28))\n", "plt.imshow(fus_bc)\n", "plt.title('Approximate Barycenter')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
countmeanstdmin25%50%75%max
Stats784.0-2.565828e-098.372986e-09-2.593707e-08-8.399538e-09-3.616124e-09-4.976524e-102.277483e-08
\n", "
" ], "text/plain": [ " count mean std min 25% \\\n", "Stats 784.0 -2.565828e-09 8.372986e-09 -2.593707e-08 -8.399538e-09 \n", "\n", " 50% 75% max \n", "Stats -3.616124e-09 -4.976524e-10 2.277483e-08 " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "error = pd.Series(f_bc - f_bc2)\n", "plt.plot(error)\n", "plt.title('Error of Aproximation')\n", "plt.xlabel(\"Pixels\")\n", "plt.ylabel('Error Values')\n", "pd.DataFrame(error.describe(), columns=['Stats']).transpose()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(12,7))\n", "\n", "total_t = [fusion_model.time, fusion_model2.time]\n", "solver_t = [fusion_model.M.getSolverDoubleInfo(\"optimizerTime\"), fusion_model2.M.getSolverDoubleInfo(\"optimizerTime\")]\n", "#Total time plot\n", "plt.subplot(1,2,1)\n", "plt.bar(['Optimal', 'Approximation'], height= total_t,\n", " width=0.4, color=(0.3, 0.6, 0.2, 0.5))\n", "plt.ylabel(\"Total Time (s)\")\n", "plt.title(\"Comparison of Total Time\")\n", "\n", "#Solver time plot\n", "plt.subplot(1,2,2)\n", "plt.bar(['Optimal', 'Approximation'], height=solver_t,\n", " width=0.4, color=(0.5, 0.6, 0.9, 0.8))\n", "plt.ylabel(\"Solver Time (s)\")\n", "plt.title(\"Comparison of Solver Time\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$\\quad$The two barycenter images that obtained from the optimal solution and approximate solution seem almost identical to each other. In addition statistical description of values of the error between them is presented above with a plot. The mean and the even extreme values are small and indicates that the reduction of time obtained by approximation totally compensates the error." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Modeling the same problem with CVXPY" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "import cvxpy as cp\n", "import time\n", "class Wasserstein_CVXPY:\n", " \n", " def __init__(self):\n", " self.time = 0.0\n", " self.result = None\n", " self.prob = None\n", "\n", " def single_pmf(self, data = None, img=False):\n", " \n", " ''' Takes a image or array of images and extracts the probabilty mass function'''\n", " \n", " if not img:\n", " v=[]\n", " for image in data:\n", " arr = np.asarray(image).ravel(order='K')\n", " v.append(arr/np.sum(arr))\n", " else:\n", " v = np.asarray(data).ravel(order='K')\n", " v = v/np.sum(v)\n", " return v\n", " \n", " def ms_distance(self, m ,n, constant=False):\n", " \n", " ''' Squared Euclidean distance calculation between the pixels '''\n", " \n", " if constant:\n", " d = np.ones((m,m))\n", " else:\n", " d = np.empty((m,m))\n", " coor = []\n", " for i in range(n):\n", " for j in range(n):\n", " coor.append(np.array([i,j]))\n", " for i in range(m):\n", " for j in range(m):\n", " d[i][j] = np.linalg.norm(coor[i]-coor[j])**2\n", " return d\n", " \n", " def Wasserstein_Distance(self, bc ,data, img = False):\n", " \n", " ''' Calculation of wasserstein distance between a barycenter and an image by solving \n", " the minimization problem '''\n", " \n", " v = np.array(self.single_pmf(data, img))\n", " n = v.shape[0]\n", " d = self.ms_distance(n,data.shape[1])\n", " \n", " pi = cp.Variable((n,n), nonneg=True)\n", " obj = cp.Minimize((np.ones(n).T @ cp.multiply(d,pi) @ np.ones(n)))\n", " \n", " Cons=[]\n", " Cons.append((np.ones(n) @ pi).T == bc)\n", " Cons.append((pi @ np.ones(n)) == v)\n", " \n", " prob = cp.Problem(obj, constraints= Cons)\n", " \n", " return prob.solve(solver=cp.MOSEK, verbose = True)\n", " \n", " def Wasserstein_BaryCenter(self,data):\n", " \n", " ''' Calculation of wasserstein barycenter of given images by solving the minimization problem '''\n", " \n", " start_time = time.time()\n", " k = data.shape[0]\n", " v = np.array(self.single_pmf(data))\n", " n = v.shape[1]\n", " d = self.ms_distance(n,data.shape[1])\n", " \n", " #Add variables\n", " pi= []\n", " t= []\n", " mu = cp.Variable(n, nonneg = True)\n", " for i in range(k):\n", " pi.append(cp.Variable((n,n), nonneg = True))\n", " t.append(cp.Variable(nonneg = True))\n", " \n", " obj = cp.Minimize(np.sum(t)/k)\n", " \n", " #Add constraints\n", " Cons=[]\n", " for i in range(k):\n", " Cons.append( t[i] >= np.ones(n).T @ cp.multiply(d,pi[i]) @ np.ones(n) ) #Constraint (1)\n", " Cons.append( (np.ones(n) @ pi[i]).T == mu) #Constraint (2)\n", " Cons.append( (pi[i] @ np.ones(n)) == v[i]) #Constraint (3)\n", " \n", " self.prob = cp.Problem(obj, constraints= Cons)\n", " self.result = self.prob.solve(solver=cp.MOSEK,verbose = True)\n", " self.time = time.time() - start_time\n", " \n", " return mu.value\n", " \n", " def Wasserstein_regBaryCenter(self,data, _lambda = None, relgap=\"1.0e-7\"):\n", " \n", " ''' Calculation of wasserstein barycenter of given \n", " images by solving a entropy regularized minimization problem '''\n", " \n", " start_time = time.time()\n", " k = data.shape[0]\n", " v = np.array(self.single_pmf(data))\n", " n = v.shape[1]\n", " d = self.ms_distance(n,data.shape[1])\n", " \n", " if not _lambda:\n", " _lambda = 60/np.median(d.ravel())\n", " \n", " #Add variables\n", " pi= []\n", " t= []\n", " mu = cp.Variable(n, nonneg = True)\n", " for i in range(k):\n", " pi.append(cp.Variable((n,n), nonneg = True))\n", " t.append(cp.Variable(nonneg = True))\n", " \n", " obj = cp.Minimize((np.sum(t) - (1/_lambda)*np.sum(cp.sum(cp.entr(pi[i])) for i in range(k)))/k)\n", " \n", " #Add constraints\n", " Cons=[]\n", " for i in range(k):\n", " Cons.append( t[i] >= (np.ones(n).T @ cp.multiply(d,pi[i]) @ np.ones(n)))#Constraint (1)\n", " Cons.append( (np.ones(n) @ pi[i]).T == mu) #Constraint (2)\n", " Cons.append( (pi[i] @ np.ones(n)) == v[i]) #Constraint (3)\n", " \n", " self.prob = cp.Problem(obj, constraints= Cons)\n", " self.result = self.prob.solve(solver=cp.MOSEK,\n", " verbose = True, \n", " mosek_params = {\"MSK_DPAR_INTPNT_CO_TOL_REL_GAP\" : relgap })\n", " self.time = time.time() - start_time\n", " \n", " return mu.value\n", " \n", " def reset(self):\n", " self.prob = None\n", " self.result = None\n" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/home/yhk/anaconda3/lib/python3.6/site-packages/ipykernel_launcher.py:116: DeprecationWarning: Calling np.sum(generator) is deprecated, and in the future will give a different result. Use np.sum(np.fromiter(generator)) or the python sum builtin instead.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "\n", "Problem\n", " Name : \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 4921172 \n", " Cones : 1229312 \n", " Scalar variables : 6147346 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer started.\n", "Presolve started.\n", "Linear dependency checker started.\n", "Linear dependency checker terminated.\n", "Eliminator started.\n", "Freed constraints in eliminator : 0\n", "Eliminator terminated.\n", "Eliminator - tries : 1 time : 0.00 \n", "Lin. dep. - tries : 1 time : 0.94 \n", "Lin. dep. - number : 1 \n", "Presolve terminated. Time: 5.52 \n", "Problem\n", " Name : \n", " Objective sense : min \n", " Type : CONIC (conic optimization problem)\n", " Constraints : 4921172 \n", " Cones : 1229312 \n", " Scalar variables : 6147346 \n", " Matrix variables : 0 \n", " Integer variables : 0 \n", "\n", "Optimizer - threads : 24 \n", "Optimizer - solved problem : the primal \n", "Optimizer - Constraints : 1138\n", "Optimizer - Cones : 1229312\n", "Optimizer - Scalar variables : 3687936 conic : 3687936 \n", "Optimizer - Semi-definite variables: 0 scalarized : 0 \n", "Factor - setup time : 1.32 dense det. time : 0.00 \n", "Factor - ML order time : 0.01 GP order time : 0.00 \n", "Factor - nonzeros before factor : 2.79e+05 after factor : 3.41e+05 \n", "Factor - dense dim. : 0 flops : 1.17e+08 \n", "ITE PFEAS DFEAS GFEAS PRSTATUS POBJ DOBJ MU TIME \n", "0 6.3e+02 5.1e+02 2.4e+07 0.00e+00 2.213290906e+07 -1.586952925e+06 1.0e+00 10.80 \n", "1 2.2e+02 1.8e+02 1.4e+07 -9.87e-01 1.997448687e+07 -3.251322359e+06 3.5e-01 13.53 \n", "2 1.4e+02 1.1e+02 1.0e+07 -8.50e-01 1.706336316e+07 -4.132584664e+06 2.2e-01 16.00 \n", "3 8.6e+01 6.9e+01 6.1e+06 -5.35e-01 1.255539057e+07 -4.350508595e+06 1.4e-01 18.47 \n", "4 3.9e+01 3.1e+01 2.3e+06 -5.91e-02 6.634396136e+06 -3.290269560e+06 6.2e-02 21.06 \n", "5 1.6e+01 1.3e+01 6.8e+05 4.56e-01 3.047707328e+06 -1.738025645e+06 2.5e-02 23.59 \n", "6 9.2e+00 7.4e+00 3.2e+05 6.93e-01 1.871307617e+06 -1.107856288e+06 1.5e-02 26.26 \n", "7 3.8e+00 3.0e+00 9.0e+04 7.82e-01 8.078374063e+05 -5.102762310e+05 5.9e-03 28.94 \n", "8 1.0e+00 8.1e-01 1.4e+04 8.51e-01 2.027566219e+05 -1.783122870e+05 1.6e-03 31.50 \n", "9 4.2e-01 3.4e-01 4.0e+03 8.87e-01 8.245390849e+04 -8.500024053e+04 6.6e-04 34.09 \n", "10 1.2e-01 9.9e-02 6.9e+02 9.00e-01 2.254812883e+04 -2.962344930e+04 2.0e-04 36.68 \n", "11 3.6e-02 2.9e-02 1.2e+02 9.02e-01 5.918677286e+03 -1.024336468e+04 5.7e-05 39.24 \n", "12 1.1e-02 8.5e-03 2.0e+01 9.00e-01 1.600641695e+03 -3.421611681e+03 1.7e-05 41.83 \n", "13 3.3e-03 2.6e-03 3.7e+00 9.03e-01 4.338561459e+02 -1.203297297e+03 5.2e-06 44.30 \n", "14 9.2e-04 7.4e-04 5.9e-01 9.15e-01 9.099180087e+01 -3.977689860e+02 1.5e-06 46.90 \n", "15 2.5e-04 2.0e-04 8.5e-02 9.22e-01 1.262938718e+00 -1.351900013e+02 3.9e-07 49.58 \n", "16 7.1e-05 5.7e-05 1.4e-02 9.31e-01 -1.815195892e+01 -5.892312187e+01 1.1e-07 52.15 \n", "17 1.6e-05 1.3e-05 1.6e-03 9.35e-01 -2.349893678e+01 -3.326489098e+01 2.6e-08 54.74 \n", "18 3.2e-06 2.6e-06 1.5e-04 9.38e-01 -2.441820572e+01 -2.642393794e+01 5.1e-09 57.33 \n", "19 7.5e-07 6.0e-07 1.7e-05 9.44e-01 -2.452958761e+01 -2.501494965e+01 1.2e-09 59.85 \n", "20 1.8e-07 1.4e-07 2.0e-06 9.49e-01 -2.454255453e+01 -2.466070613e+01 2.8e-10 62.42 \n", "21 3.6e-08 2.9e-08 1.9e-07 9.48e-01 -2.454079667e+01 -2.456580565e+01 5.7e-11 65.00 \n", "22 9.3e-09 7.5e-09 2.6e-08 9.50e-01 -2.453852207e+01 -2.454516536e+01 1.5e-11 67.53 \n", "23 2.3e-09 1.8e-09 3.3e-09 9.51e-01 -2.453774797e+01 -2.453943362e+01 3.6e-12 70.11 \n", "24 6.9e-10 5.0e-10 4.7e-10 9.51e-01 -2.453754486e+01 -2.453801407e+01 9.8e-13 72.59 \n", "Optimizer terminated. Time: 74.99 \n", "\n", "\n", "Interior-point solution summary\n", " Problem status : PRIMAL_AND_DUAL_FEASIBLE\n", " Solution status : OPTIMAL\n", " Primal. obj: -2.4537544857e+01 nrm: 4e+00 Viol. con: 1e-08 var: 0e+00 cones: 6e-12 \n", " Dual. obj: -2.4538014075e+01 nrm: 8e+02 Viol. con: 7e-15 var: 1e-08 cones: 0e+00 \n", "\n", "Time Spent to solve problem with CVXPY: \n", " 102.05331134796143\n", "Time Spent in solver: \n", " 74.98805212974548\n", "The average Wasserstein distance between digits and the barycenter: \n", " -24.537544856968044\n" ] } ], "source": [ "cvxpy_model = Wasserstein_CVXPY()\n", "cvxpy_result = cvxpy_model.Wasserstein_regBaryCenter(train, relgap = 1.0e-3)\n", "print('\\nTime Spent to solve problem with CVXPY: \\n {0}'.format(cvxpy_model.time))\n", "print('Time Spent in solver: \\n {0}'.format(cvxpy_model.prob.solver_stats.solve_time))\n", "print('The average Wasserstein distance between digits and the barycenter: \\n {0}'.format(cvxpy_model.result))" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "scrolled": true }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.imshow(np.reshape(cvxpy_result.squeeze(), (28,28)))\n", "plt.title('Barycenter')\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.figure(figsize=(12,6))\n", "\n", "total_t50 = [fusion_model2.time, cvxpy_model.time]\n", "solver_t50 = [fusion_model2.M.getSolverDoubleInfo(\"optimizerTime\"), cvxpy_model.prob.solver_stats.solve_time]\n", "\n", "#Total time plot\n", "plt.subplot(1,2,1)\n", "plt.bar(['Fusion', 'CVXPY'], height= total_t50,\n", " width=0.4, color=(0.3, 0.6, 0.2, 0.5))\n", "plt.ylabel(\"Total Time (s)\")\n", "plt.title(\"Comparison of Total Time\")\n", "\n", "#Solver time plot\n", "plt.subplot(1,2,2)\n", "plt.bar(['Fusion','CVXPY'], height=solver_t50,\n", " width=0.4, color=(0.5, 0.6, 0.9, 0.8))\n", "plt.ylabel(\"Solver Time (s)\")\n", "plt.title(\"Comparison of Solver Time\")\n", "plt.show()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Creative
This work is licensed under a Creative Commons Attribution 4.0 International License. The **MOSEK** logo and name are trademarks of Mosek ApS. The code is provided as-is. Compatibility with future release of **MOSEK** or the `Fusion API` are not guaranteed. For more information contact our [support](mailto:support@mosek.com). " ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.4" } }, "nbformat": 4, "nbformat_minor": 2 }