Experiment 10: TRo Journal


Create videos to inspect latent space of markers


In [ ]:
# import the modules
import sys
import GPy
import csv
import numpy as np
import cPickle as pickle
import matplotlib as mpl
import matplotlib.cm as cm
import scipy.stats as stats
from GPy.plotting import Tango
import sklearn.metrics as metrics
from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from GPy.plotting.matplot_dep.visualize import matplotlib_show

%matplotlib notebook

In [ ]:
font = {'size' : 18}

mpl.rc('font', **font)

Data Loading



In [ ]:
# load all the files and create Data
mocapPath = '../Data/Exp9/'

names = ['K1S1P1T1','K1S1P2T1','K1S1P6T1']

nTypes = 1
paths = [mocapPath]
dataKeys = ['Marker']
dataFormats = ['Marker']

# read all the file names and save to dicts
Data = {}
# loop over all names
for fileName in names:
    data = {}
    for ind in range(nTypes):
        dataName = paths[ind] + fileName + dataFormats[ind] 
        reader = csv.reader(open(dataName,"rb"), delimiter=',')

        d = np.array(list(reader))
        data[dataKeys[ind]] = d.astype('float')        
    Data[fileName] = data

In [ ]:
# create train, val and test data
dim = 36
key = 'Marker'
samplingFreq = 2

trainSize = 0
trainData = np.empty((0,dim))    
trainNames = ['K1S1P1T1']

for fileName in trainNames:
    trainData = np.concatenate((trainData,Data[fileName][key][::samplingFreq,:]),axis=0)
trainSize = trainData.shape[0]

#trainData[:,0::3] = -trainData[:,0::3]
#trainData[:,2::3] = -trainData[:,2::3]

Bayesian Model Training



In [ ]:
# Training Cloud BGPLVM Model

# model name
expName = 'bgplvmModel'

# set the overall parameters for bgplvm
qDim = 10
nSamples = trainData.shape[0]

# set the number of inducing inputs
nInducing = 100

In [ ]:
from sklearn.decomposition import PCA

pca = PCA(n_components=qDim)
pca.fit(trainData)

scalesPCA = pca.explained_variance_ratio_
scalesPCA = scalesPCA/scalesPCA.max()

trainX = pca.transform(trainData)
trainOut = pca.inverse_transform(trainX)

In [ ]:
# setting up the kernel
kernel = GPy.kern.RBF(qDim, variance=1., lengthscale=1./scalesPCA, ARD = True)

# exepriment with different X initializations
bgplvmModel = GPy.models.BayesianGPLVM(trainData,input_dim=qDim,num_inducing=nInducing,kernel=kernel,X=trainX)

# Phase 1: Optimizaition by fixing variance parameters
SNR = 1000
var = bgplvmModel.Y.var()

bgplvmModel.rbf.variance.fix(var)
bgplvmModel.Gaussian_noise.variance.fix(var/SNR)

initVardistIters = 100
bgplvmModel.optimize(messages=True, max_iters=initVardistIters)

# Phase 2: Optimize the model without any constraints

# training without constraints
trainIters = 1000
bgplvmModel.unconstrain_fixed()
bgplvmModel.optimize(messages=True, max_iters=trainIters)

# Save the model to file
pickle.dump(bgplvmModel,open('../Models/Exp9/model.p','wb'))

Experiment with Cloth Play Functions



In [ ]:
class cloth_show(matplotlib_show):
    """Base class for visualizing motion capture data."""

    def __init__(self, vals, limits, axes=None, connect=None, color='b'):
        if axes==None:
            fig = plt.figure()
            axes = fig.add_subplot(111, projection='3d', aspect='equal')

        if len(vals.shape)==1:
            vals = vals[None,:]

        matplotlib_show.__init__(self, vals, axes)

        self.color = color
        self.limits = limits
        self.connect = connect
        
        self.process_values()
        
        self.initialize_axes()
        self.axes.set_xticklabels([])
        self.axes.set_yticklabels([])
        self.axes.set_zticklabels([])
        self.axes.set_xlabel('X Axis')
        self.axes.set_ylabel('Y Axis')
        self.axes.set_zlabel('Z Axis')
        
        self.draw_edges()
        self.draw_vertices()
        self.axes.figure.canvas.draw()

    def draw_vertices(self):
        self.points_handle = self.axes.scatter(self.vals[:, 0], self.vals[:, 1], self.vals[:, 2], color=self.color)

    def draw_edges(self):
        self.line_handle = []
        if self.connect != None:
            x = []
            y = []
            z = []
            self.I, self.J = np.nonzero(self.connect)
            for i, j in zip(self.I, self.J):
                x.append(self.vals[i, 0])
                x.append(self.vals[j, 0])
                x.append(np.NaN)
                y.append(self.vals[i, 1])
                y.append(self.vals[j, 1])
                y.append(np.NaN)
                z.append(self.vals[i, 2])
                z.append(self.vals[j, 2])
                z.append(np.NaN)
            self.line_handle = self.axes.plot(np.array(x), np.array(y), np.array(z), '-', color=self.color)

    def modify(self, vals):
        if len(vals.shape)==1:
            vals = vals[None,:]
        self.vals = vals.copy()
        
        self.axes_modify()
        self.process_values()
        
        self.draw_edges()
        self.draw_vertices()
        self.axes.figure.canvas.draw()

    def process_values(self):
        self.vals = self.vals.T.reshape((self.vals.shape[1]/3, 3))

    def initialize_axes(self, boundary=0.001):
        """Set up the axes with the right limits and scaling."""
        bs = [(self.limits[i,0]-self.limits[i,1])*boundary for i in range(3)]
        self.axes.set_xlim([self.limits[0,1]-bs[0], self.limits[0,0]+bs[0]])
        self.axes.set_ylim([self.limits[1,1]-bs[1], self.limits[1,0]+bs[1]])
        self.axes.set_zlim([self.limits[2,1]-bs[2], self.limits[2,0]+bs[2]])

    def axes_modify(self):
        self.points_handle.remove()
        if self.connect != None:
            self.line_handle[0].remove()

In [ ]:
connect = np.asarray([[0,1,0,0,0,1,0,0,0,0,0,0],
                      [1,0,1,0,0,0,0,0,0,0,0,0],
                      [0,1,0,1,0,0,0,0,0,0,0,0],
                      [0,0,1,0,1,0,0,0,0,0,0,0],
                      [0,0,0,1,0,1,0,0,0,0,0,0],
                      [1,0,0,0,1,0,0,0,0,0,0,0],
                      [0,0,0,0,0,0,0,2,2,0,0,0],
                      [0,0,0,0,0,0,2,0,2,0,0,0],
                      [0,0,0,0,0,0,2,2,0,0,0,0],
                      [0,0,0,0,0,0,0,0,0,0,2,2],
                      [0,0,0,0,0,0,0,0,0,2,0,2],
                      [0,0,0,0,0,0,0,0,0,2,2,0]])

In [ ]:
model = pickle.load(open('../Models/Exp9/model.p','rb'))
        
fig, (latent_axes, sense_axes) = plt.subplots(1, 2)
plt.sca(latent_axes)
model.plot_latent(ax=latent_axes,marker='o')
latent_axes.set_xticks([])
latent_axes.set_yticks([])

limits = np.asarray([[trainData[:,0::3].max(),trainData[:,0::3].min()],
                     [trainData[:,1::3].max(),trainData[:,1::3].min()],
                     [trainData[:,2::3].max(),trainData[:,2::3].min()]])
data_show = cloth_show(trainData[0,:], limits, connect=connect)
dim_select = lvm_dimselect(model.X.mean[0, :].copy(), model, data_show, 
                           latent_axes=latent_axes, sense_axes=sense_axes)
sense_axes.set_ylabel('ARD Weight', fontsize=15)
sense_axes.set_xlabel('Latent Dimensions', fontsize=15)
fig.canvas.draw()

LVM Classes



In [ ]:
class lvm(matplotlib_show):
    def __init__(self, vals, model, data_visualize, latent_axes=None, sense_axes=None, latent_index=[0,1], disable_drag=False):
        """Visualize a latent variable model

        :param model: the latent variable model to visualize.
        :param data_visualize: the object used to visualize the data which has been modelled.
        :type data_visualize: visualize.data_show  type.
        :param latent_axes: the axes where the latent visualization should be plotted.
        """
        if vals is None:
            if isinstance(model.X, VariationalPosterior):
                vals = model.X.mean.values
            else:
                vals = model.X.values
        if len(vals.shape)==1:
            vals = vals[None,:]
        matplotlib_show.__init__(self, vals, axes=latent_axes)

        if isinstance(latent_axes,mpl.axes.Axes):
            self.cid = latent_axes.figure.canvas.mpl_connect('button_press_event', self.on_click)
            if not disable_drag:
                self.cid = latent_axes.figure.canvas.mpl_connect('motion_notify_event', self.on_move)
            self.cid = latent_axes.figure.canvas.mpl_connect('axes_leave_event', self.on_leave)
            self.cid = latent_axes.figure.canvas.mpl_connect('axes_enter_event', self.on_enter)
        else:
            self.cid = latent_axes[0].figure.canvas.mpl_connect('button_press_event', self.on_click)
            if not disable_drag:
                self.cid = latent_axes[0].figure.canvas.mpl_connect('motion_notify_event', self.on_move)
            self.cid = latent_axes[0].figure.canvas.mpl_connect('axes_leave_event', self.on_leave)
            self.cid = latent_axes[0].figure.canvas.mpl_connect('axes_enter_event', self.on_enter)

        self.data_visualize = data_visualize
        self.model = model
        self.latent_axes = latent_axes
        self.sense_axes = sense_axes
        self.called = False
        self.move_on = False
        self.latent_index = latent_index
        self.latent_dim = model.input_dim
        self.disable_drag = disable_drag

        # The red cross which shows current latent point.
        self.latent_values = vals
        self.latent_handle = self.latent_axes.plot([0],[0],'rx',mew=2)[0]
        self.modify(vals)
        self.show_sensitivities()

    def modify(self, vals):
        """When latent values are modified update the latent representation and ulso update the output visualization."""
        self.vals = vals.view(np.ndarray).copy()
        y = self.model.predict(self.vals)[0]
        self.data_visualize.modify(y)
        self.latent_handle.set_data(self.vals[0,self.latent_index[0]], self.vals[0,self.latent_index[1]])
        self.axes.figure.canvas.draw()


    def on_enter(self,event):
        pass
    def on_leave(self,event):
        pass

    def on_click(self, event):
        if event.inaxes!=self.latent_axes: return
        if self.disable_drag:
            self.move_on = True
            self.called = True
            self.on_move(event)
        else:
            self.move_on = not self.move_on
            self.called = True

    def on_move(self, event):
        if event.inaxes!=self.latent_axes: return
        if self.called and self.move_on:
            # Call modify code on move
            self.latent_values[:, self.latent_index[0]]=event.xdata
            self.latent_values[:, self.latent_index[1]]=event.ydata
            self.modify(self.latent_values)

    def show_sensitivities(self):
        # A click in the bar chart axis for selection a dimension.
        if self.sense_axes != None:
            self.sense_axes.cla()
            self.sense_axes.bar(np.arange(self.model.input_dim), self.model.input_sensitivity(), color='b')

            if self.latent_index[1] == self.latent_index[0]:
                self.sense_axes.bar(np.array(self.latent_index[0]), self.model.input_sensitivity()[self.latent_index[0]], color='y', label='X Axis')
                self.sense_axes.bar(np.array(self.latent_index[1]), self.model.input_sensitivity()[self.latent_index[1]], color='y', label='Y Axis')

            else:
                self.sense_axes.bar(np.array(self.latent_index[0]), self.model.input_sensitivity()[self.latent_index[0]], color='g', label='X Axis')
                self.sense_axes.bar(np.array(self.latent_index[1]), self.model.input_sensitivity()[self.latent_index[1]], color='r',label='Y Axis')

        self.sense_axes.legend()
        self.sense_axes.set_xticks([])
        self.sense_axes.set_yticks([])
        self.sense_axes.figure.canvas.draw()

In [ ]:
class lvm_dimselect(lvm):
    """
    A visualizer for latent variable models which allows selection of the latent dimensions to use by clicking on a bar chart of their length scales.

    For an example of the visualizer's use try:

    GPy.examples.dimensionality_reduction.BGPVLM_oil()

    """
    def __init__(self, vals, model, data_visualize, latent_axes=None, sense_axes=None, latent_index=[0, 1], labels=None):
        if latent_axes==None and sense_axes==None:
            self.fig,(latent_axes,self.sense_axes) = plt.subplots(1,2)
        elif sense_axes==None:
            fig=plt.figure()
            self.sense_axes = fig.add_subplot(111)
        else:
            self.sense_axes = sense_axes
        self.labels = labels
        lvm.__init__(self,vals,model,data_visualize,latent_axes,sense_axes,latent_index)
        self.show_sensitivities()
        print(self.latent_values)
        print("use left and right mouse buttons to select dimensions")


    def on_click(self, event):
        if event.inaxes==self.sense_axes:
            new_index = max(0,min(int(np.round(event.xdata-0.5)),self.model.input_dim-1))
            if event.button == 1:
                # Make it red if and y-axis (red=port=left) if it is a left button click
                self.latent_index[1] = new_index
            else:
                # Make it green and x-axis (green=starboard=right) if it is a right button click
                self.latent_index[0] = new_index

            self.show_sensitivities()

            self.latent_axes.cla()
            self.model.plot_latent(which_indices=self.latent_index,
                                   ax=self.latent_axes, labels=self.labels)
            self.latent_handle = self.latent_axes.plot([0],[0],'rx',mew=2)[0]
            self.modify(self.latent_values)

        elif event.inaxes==self.latent_axes:
            self.move_on = not self.move_on

        self.called = True



    def on_leave(self,event):
        print(type(self.latent_values))
        latent_values = self.latent_values.copy()
        y = self.model.predict(latent_values[None,:])[0]
        self.data_visualize.modify(y)