def __init__( self, n_units, sig_level=2, train_time_lapse=False, initial_time_lapse=0.1, output_signatures=False, #whether the output includes the signatures use_signatures=True, #whether each new state can depend on the signature kernel_initializer='glorot_uniform', recurrent_initializer='he_normal', #could be good to use 'orthogonal' if not use_signatures activation='tanh', #not applied to signature elements **kwargs): self.sig_level = sig_level self.sigsize = iisignature.siglength(2, sig_level) self.n_units = n_units #like output_dim self.units = n_units * (self.sigsize + 1) if output_signatures else n_units self.train_time_lapse = train_time_lapse self.initial_time_lapse = initial_time_lapse self.output_signatures = output_signatures self.use_signatures = use_signatures self.kernel_initializer = initializers.get(kernel_initializer) self.recurrent_initializer = initializers.get(recurrent_initializer) self.activation = activations.get(activation) super(RecurrentSig, self).__init__(**kwargs)
def __init__(self, ef_num_hlayers, ef_num_hu, ef_num_filters, pslevel, num_slices, dropout): ''' for each diagram, we have different slices Across different functions, we have the same parameters for #h0slices, #h0siglevel, #h1slices, #h1siglevel ''' super(dgmslice_ps2, self).__init__() self.filters = ef_num_filters self.pslevel = pslevel #list [pslevel for h0, pslevel for h1] self.slices = num_slices #list [#slices for h0, #slices for pslevel for h1] #self.siglength = [iisignature.siglength(num_slices+1, m) for m in pslevel] self.siglength = [ iisignature.siglength(num_slices[i], pslevel[i]) for i in range(2) ] # self.eigfs = nn.ModuleList() self.projections0 = nn.ModuleList() self.projections1 = nn.ModuleList() self.final_vec_length = self.filters * sum(self.siglength) for i in range(self.filters): self.eigfs.append(eigf(ef_num_hlayers, ef_num_hu)) for i in range(self.filters): self.projections0.append(nn.Conv1d(1, self.slices[0], 2, 2)) for i in range(self.filters): self.projections1.append(nn.Conv1d(1, self.slices[1], 2, 2)) self.final_layer = nn.Sequential(nn.Dropout(dropout), nn.Linear(self.final_vec_length, 1), nn.BatchNorm1d(1))
def testcombining(self): dim = 2 level = 2 siglength = iisignature.siglength(dim,level) pathLength = 20 halfPathLength=10 numberToDo=4 path = numpy.random.uniform(size=(numberToDo,pathLength,dim)) sig = iisignature.sig(path,level) sig1 = iisignature.sig(path[:,:halfPathLength],level) sig2 = iisignature.sig(path[:,(halfPathLength-1):],level) combined = iisignature.sigcombine(sig1,sig2,dim,level) self.assertLess(diff(sig,combined),0.0001) extra = numpy.random.uniform(size=(siglength,)) bumpedsig1 = 1.001 * sig1 bumpedsig2 = 1.001 * sig2 base = numpy.sum(iisignature.sigcombine(sig1,sig2,dim,level)) bump1 = numpy.sum(iisignature.sigcombine(bumpedsig1,sig2,dim,level)) bump2 = numpy.sum(iisignature.sigcombine(sig1,bumpedsig2,dim,level)) derivsOfSum = numpy.ones((numberToDo,siglength)) calculated = iisignature.sigcombinebackprop(derivsOfSum,sig1,sig2,dim,level) self.assertEqual(len(calculated), 2) diff1 = (bump1 - base) - numpy.sum(calculated[0] * (bumpedsig1 - sig1)) diff2 = (bump2 - base) - numpy.sum(calculated[1] * (bumpedsig2 - sig2)) #print ("\n",bump1,bump2,base,diff1,diff2) self.assertLess(numpy.abs(diff1),0.000001) self.assertLess(numpy.abs(diff2),0.00001)
def testFewPoints(self): # check sanity of paths with less than 3 points path1=[[4.3,0.8]] path2=numpy.array([[1,2],[2,4]]) m=4 d=2 s=iisignature.prepare(d,m,"cosx") s_a=iisignature.prepare(d,2,"cosx") length=iisignature.siglength(d,m) loglength=iisignature.logsiglength(d,m) loglength_a=iisignature.logsiglength(d,2) blankLogSig=numpy.zeros(loglength) blankLogSig_a=numpy.zeros(loglength_a) blankSig=numpy.zeros(length) self.assertLess(diff(iisignature.sig(path1,m),blankSig),0.000000001) self.assertTrue(numpy.array_equal(iisignature.sig(path1,m,2),numpy.zeros([0,length]))) self.assertLess(diff(iisignature.logsig(path1,s,"C"),blankLogSig),0.000000001) self.assertLess(diff(iisignature.logsig(path1,s,"O"),blankLogSig),0.000000001) self.assertLess(diff(iisignature.logsig(path1,s,"S"),blankLogSig),0.000000001) self.assertLess(diff(iisignature.logsig(path1,s,"X"),blankSig),0.000000001) self.assertLess(diff(iisignature.logsig(path1,s_a,"A"),blankLogSig_a),0.000000001) blankLogSig[:d]=path2[1]-path2[0] blankLogSig_a[:d]=path2[1]-path2[0] blankSig[:d]=path2[1]-path2[0] self.assertLess(diff(iisignature.logsig(path2,s,"C"),blankLogSig),0.000001) self.assertLess(diff(iisignature.logsig(path2,s,"O"),blankLogSig),0.000001) self.assertLess(diff(iisignature.logsig(path2,s,"S"),blankLogSig),0.000001) self.assertLess(diff(iisignature.logsig(path2,s,"X"),blankSig),0.000001) self.assertLess(diff(iisignature.logsig(path2,s_a,"A"),blankLogSig_a),0.000001)
def __init__(self, input_size, n_units, sig_level=2, train_time_lapse=True, initial_time_lapse=0.1, output_signatures=False, use_signatures=True): super(RecurrentSig, self).__init__() self.sig_level = sig_level self.sigsize = iisignature.siglength(2, sig_level) self.n_units = n_units self.units = n_units * (self.sigsize + 1) if output_signatures else n_units self.train_time_lapse = train_time_lapse #self.initial_time_lapse = initial_time_lapse self.output_signatures = output_signatures self.use_signatures = use_signatures saved_data_length = self.n_units * (1 + self.sigsize if self.use_signatures else 1) self.W = nn.Linear(input_size, self.n_units) self.U = nn.Linear(saved_data_length, self.n_units) if self.train_time_lapse: self.log_timelapse = nn.parameter.Parameter( torch.FloatTensor([math.log(initial_time_lapse)])) else: self.time_lapse = Variable(torch.FloatTensor([initial_time_lapse]))
def get_penalization(self, n, k, Kpen): """Returns the penalization function used in the estimator of the truncation order, that is, pen_n(k)=Kpen*sqrt((d^(k+1)-1)/(d-1))/n^rho. Parameters ---------- n: int Number of samples. k: int Truncation order of the signature. Kpen: float, default=1 Constant in front of the penalization, it has to be strictly positive. Returns ------- pen_n(k):float The penalization pen_n(k) """ if k == 0: size_sig = 1 else: size_sig = isig.siglength(self.d, k) + 1 return Kpen * n**(-self.rho) * math.sqrt(size_sig)
def get_sigX(X, k): """Returns a matrix containing signatures truncated at k of n samples given in the input tensor X. Parameters ---------- X: array, shape (n, npoints, d) A 3-dimensional array, containing the coordinates in R^d of n piecewise linear paths, each composed of n_points. k: int Truncation order of the signature Returns ------- sigX: array, shape (n,p) A matrix containing in each row the signature truncated at k of a sample. """ if k == 0: return np.full((np.shape(X)[0], 1), 1) else: d = X.shape[2] sigX = np.zeros((np.shape(X)[0], isig.siglength(d, k) + 1)) sigX[:, 0] = 1 for i in range(np.shape(X)[0]): sigX[i, 1:] = isig.sig(X[i, :, :], k) return sigX
def consistency(self, coropa, dim, level): #numpy.random.seed(21) s = iisignature.prepare(dim,level,"coshx" if coropa else "cosx") myinfo = {"level":level, "dimension":dim, "methods": ("COSAX" if level <= 2 else "COSX"), "basis":("Standard Hall" if coropa else "Lyndon")} self.assertEqual(iisignature.info(s),myinfo) path = numpy.random.uniform(size=(10,dim)) basis = iisignature.basis(s) logsig = iisignature.logsig(path,s) sig = iisignature.sig(path,level) #check lengths self.assertEqual(len(basis),iisignature.logsiglength(dim,level)) self.assertEqual((len(basis),),logsig.shape) self.assertEqual(sig.shape,(iisignature.siglength(dim,level),)) #calculate a signature from logsig expanded_logsig = [numpy.zeros(dim ** m) for m in range(1,level + 1)] for coeff, expression in zip(logsig,basis): values, depth = valueOfBracket(expression,dim) expanded_logsig[depth - 1]+=values * coeff calculated_sig = numpy.concatenate(exponentiateTensor(expanded_logsig)) self.assertLess(diff(sig,calculated_sig),0.00001) #calculate a log signature from sig fullLogSig = numpy.concatenate(logTensor(splitConcatenatedTensor(sig,dim,level))) fullLogSigLib = iisignature.logsig(path,s,"x") diff1 = numpy.max(numpy.abs(fullLogSigLib - fullLogSig)) #print #(numpy.vstack([fullLogSig,fullLogSigLib,numpy.abs(fullLogSigLib-fullLogSig)]).transpose()) self.assertLess(diff1,0.00001) basisMatrix = [] zeros = [numpy.zeros(dim ** m) for m in range(1,level + 1)] for expression in basis: values, depth = valueOfBracket(expression, dim) temp = zeros[depth - 1] zeros[depth - 1] = values basisMatrix.append(numpy.concatenate(zeros)) zeros[depth - 1] = temp calculatedLogSig = lstsq(numpy.transpose(basisMatrix),fullLogSig)[0] diff2 = numpy.max(numpy.abs(logsig - calculatedLogSig)) self.assertLess(diff2,0.00001) #check consistency of methods slowLogSig = iisignature.logsig(path,s,"o") diffs = numpy.max(numpy.abs(slowLogSig - calculatedLogSig)) self.assertLess(diffs,0.00001) sigLogSig = iisignature.logsig(path,s,"s") diffs = numpy.max(numpy.abs(sigLogSig - calculatedLogSig)) self.assertLess(diffs,0.00001) if level < 3: areaLogSig = iisignature.logsig(path,s,"a") diffs = numpy.max(numpy.abs(areaLogSig - calculatedLogSig)) self.assertLess(diffs,0.00001)
def infer_shape(self,node,shapes): #d=shapes[0][-1] s,method=_prepared_obeject_store[node.inputs[1].get_value()] m=iisignature.info(s)["level"] d=iisignature.info(s)["dimension"] if "x" in method or "X" in method: length=iisignature.siglength(d,m) else: length=iisignature.logsiglength(d,m) return [shapes[0][:-2]+(length,)]
def get_sig_dimension(self): """ Returns the dimension of the signature vector truncated at self.order and with the embedding chosen by self.path Returns ------- siglength: int The dimension of the signature vector. """ return (isig.siglength(self.get_embedding_dimension(), self.order))
def delayedBM_limit(BM_1d, depth, time): """Returns limiting rough path in p-var top for the delayed BM problem (with iisignature and BnB)""" N = len(BM_1d) X_inf = np.zeros((N, iisignature.siglength(2, depth))) for k, t in enumerate(time): X_inf[k, 0] = BM_1d[k] X_inf[k, 1] = BM_1d[k] X_inf[k, 2] = 0. X_inf[k, 3] = t / 2. X_inf[k, 4] = -t / 2. X_inf[k, 5] = 0. return X_inf
def testSig(self): #test that sigjacobian and sigbackprop compatible with sig numpy.random.seed(291) d = 3 m = 5 pathLength = 10 path = numpy.random.uniform(size=(pathLength,d)) path = numpy.cumsum(2 * (path - 0.5),0)#makes it more random-walk-ish, less like a scribble increment = 0.01 * numpy.random.uniform(size=(pathLength,d)) base_sig = iisignature.sig(path,m) target = fdDeriv(lambda x:iisignature.sig(x,m),path,increment,2, nosum=True) gradient = iisignature.sigjacobian(path,m) calculated = numpy.tensordot(increment,gradient) diffs = numpy.max(numpy.abs(calculated - target)) niceOnes = numpy.abs(calculated) > 1.e-4 niceOnes2 = numpy.abs(calculated) < numpy.abs(base_sig) diffs1 = numpy.max(numpy.abs((calculated[niceOnes2] - target[niceOnes2]) / base_sig[niceOnes2])) diffs2 = numpy.max(numpy.abs(calculated[1 - niceOnes2] - target[1 - niceOnes2])) ratioDiffs = numpy.max(numpy.abs(calculated[niceOnes] / target[niceOnes] - 1)) #numpy.set_printoptions(suppress=True,linewidth=os.popen('stty size', #'r').read().split()[1] #LINUX #numpy.set_printoptions(suppress=True,linewidth=150) #print ("") #print (path) #print #(numpy.vstack([range(len(base_sig)),base_sig,calculated,target,(calculated-target)/base_sig,calculated/target-1]).transpose()) #print (diffs, ratioDiffs, diffs1, diffs2) #print(numpy.argmax(numpy.abs(calculated[niceOnes]/target[niceOnes]-1)),numpy.argmax(numpy.abs((calculated-target)/base_sig))) self.assertLess(diffs,0.00001) self.assertLess(ratioDiffs,0.01) self.assertLess(diffs1,0.001) self.assertLess(diffs2,0.00001) #compatibility between sigbackprop and sigjacobian is strong dFdSig = numpy.random.uniform(size=(iisignature.siglength(d,m),)) backProp = iisignature.sigbackprop(dFdSig,path,m) manualCalcBackProp = numpy.dot(gradient,dFdSig) backDiffs = numpy.max(numpy.abs(backProp - manualCalcBackProp)) if 0: # to investigate the compile logic problem I used this and # (d,m,pathLength)=(1,2,2) print("") print(dFdSig) print(path) print(backProp) print(manualCalcBackProp) self.assertLess(backDiffs,0.000001)
def __init__(self, trend, init_money=10000, window_size=20): #这里把df改为trend self.n_actions = 3 # 动作数量 self.n_features = window_size + iisignature.siglength(2, 3) # 特征数量 #self.trend = df['close'].values # 收盘数据 #self.df = df #数据的DataFrame self.trend = trend # 收盘数据 self.init_money = init_money # 初始化资金 self.n_lagged_time_steps = 20 #用于计算signature的p-lag value 200 self.window_size = window_size #滑动窗口大小 self.half_window = window_size // 2 #self.signature = np.empty(shape=[len(self.trend),iisignature.siglength(2,3)]) self.signature = self.signature_normalisation(self.trend)
def logSig(self, type, m=5): numpy.random.seed(291) d=2 pathLength=10 s=iisignature.prepare(d,m,type) path = numpy.random.uniform(size=(pathLength,d)) path = numpy.cumsum(2 * (path - 0.5),0)#makes it more random-walk-ish, less like a scribble increment = 0.01*path increment = 0.1*numpy.random.uniform(size=(pathLength,d)) manualChange = fdDeriv(lambda x:iisignature.logsig(x,s,type),path,increment,4) dFdlogSig = numpy.ones(iisignature.siglength(d,m) if "X"==type else iisignature.logsiglength(d,m)) calculatedChange = numpy.sum(increment*iisignature.logsigbackprop(dFdlogSig,path,s,type)) #print(manualChange, calculatedChange) self.assertLess(numpy.abs(manualChange-calculatedChange),0.0001)
def delayed_roughBM(BM, BM_del, delay, depth, time): if delay == 0: return delayedBM_limit(BM, depth, time) BM = np.concatenate((BM, np.array(delay * [BM[-1]])), 0) N = len(BM) roughBM = np.zeros((N, iisignature.siglength(2, depth))) DeltaBM = np.append(0., np.diff(BM, 0)) for k in range(N): roughBM[k, 0] = BM[k] roughBM[k, 1] = BM_del[k] roughBM[k, 2] = 0. levy_area = (BM_del[:k] * DeltaBM[:k]).sum() - 0.5 * BM[k] * BM_del[k] roughBM[k, 3] = levy_area roughBM[k, 4] = -levy_area roughBM[k, 5] = 0. return roughBM
def testjoining(self): numberToDo = 1 dim = 2 level = 2 siglength = iisignature.siglength(dim,level) for fixedPoint, inputDim, fixed in [(float('nan'),dim,False),(0.1,dim - 1,True)]: pathLength = 10 def makePath(): p = numpy.random.uniform(size=(pathLength,dim)) if fixed: p[:,-1] = fixedPoint * numpy.arange(pathLength) return p paths = [makePath() for i in range(numberToDo)] sig = numpy.vstack([iisignature.sig(path,level) for path in paths]) joinee = numpy.zeros((numberToDo,siglength)) for i in range(1,pathLength): displacements = [path[i:(i + 1),:] - path[(i - 1):i,:] for path in paths] displacement = numpy.vstack(displacements) if fixed: displacement = displacement[:,:-1] joinee = iisignature.sigjoin(joinee,displacement,level,fixedPoint) self.assertLess(diff(sig,joinee),0.0001,"fullSig matches sig" + (" with fixed Dim" if fixed else "")) extra = numpy.random.uniform(size=(numberToDo,inputDim)) bumpedExtra = 1.001 * extra bumpedJoinee = 1.001 * joinee base = numpy.sum(iisignature.sigjoin(joinee,extra,level,fixedPoint)) bump1 = numpy.sum(iisignature.sigjoin(bumpedJoinee,extra,level,fixedPoint)) bump2 = numpy.sum(iisignature.sigjoin(joinee,bumpedExtra,level,fixedPoint)) derivsOfSum = numpy.ones((numberToDo,siglength)) calculated = iisignature.sigjoinbackprop(derivsOfSum,joinee,extra, level,fixedPoint) self.assertEqual(len(calculated),3 if fixed else 2) diff1 = (bump1 - base) - numpy.sum(calculated[0] * (bumpedJoinee - joinee)) diff2 = (bump2 - base) - numpy.sum(calculated[1] * (bumpedExtra - extra)) #print ("\n",bump1,bump2,base,diff1,diff2) self.assertLess(numpy.abs(diff1),0.000001,"diff1 as expected " + (" with fixed Dim" if fixed else "")) self.assertLess(numpy.abs(diff2),0.00001,"diff2 as expected " + (" with fixed Dim" if fixed else "")) if fixed: bumpedFixedPoint = fixedPoint * 1.01 bump3 = numpy.sum(iisignature.sigjoin(joinee,extra, level, bumpedFixedPoint)) diff3 = (bump3-base - numpy.sum(calculated[2] * (bumpedFixedPoint-fixedPoint))) #print("\n",bump3,base, fixedPoint, bumpedFixedPoint, calculated[2]) self.assertLess(numpy.abs(diff3),0.00001, "diff3")
def __init__( self, n_hidden, sig_dimension, sig_level=2, kernel_initializer='glorot_uniform', #inner_init='he_normal',#could be good to use 'orthogonal' - not used activation='tanh', #not applied to signature elements **kwargs): self.n_hidden = n_hidden self.units = n_hidden self.sig_dimension = sig_dimension self.sig_level = sig_level self.sigsize = iisignature.siglength(sig_dimension, sig_level) self.kernel_initializer = initializers.get(kernel_initializer) self.activation = activations.get(activation) self.states = [None, None] super(LSTMSig, self).__init__(**kwargs)
def get_Y_sig(self, X, mast, noise_std=100, plot=False): """Compute the target values Y as scalar products of the truncated signatures of rows of X with a certain parameter beta plus a gaussian noise. Y follows therefore the signature linear model. Parameters ---------- X: array, shape (n, self.npoints, self.d) Array of paths. It is a 3-dimensional array, containing the coordinates in R^d of n piecewise linear paths, each composed of npoints. mast: int True value of the truncation order of the signature. noise_std: float, default=100 Amount of noise of Y, Y is equal to the scalar product of the signature of X against beta plus a uniform noise on [-noise_std,noise_std]. plot: boolean, default=False If True, output two plots: one plot with the signature coefficients of one sample and the regression vector beta, one scatter plot with Y against Y+noise to check the calibration of the noise variance. Returns ------- Y: array, shape (n) Target values """ n = X.shape[0] if mast == 0: size_sig = 1 else: size_sig = isig.siglength(self.d, mast) + 1 beta = np.random.random(size=size_sig) / 1000 noise = 2 * noise_std * np.random.random(size=n) - noise_std SigX = get_sigX(X, mast) beta_repeated = np.repeat(beta.reshape(1, size_sig), n, axis=0) Y = np.sum(beta_repeated * SigX, axis=1) if plot: plt.scatter(Y, Y + noise) plt.title("Y against Y+noise") plt.show() return Y + noise
def __init__(self, ef_num_hlayers, ef_num_hu, ef_num_filters, pslevel, num_slices, dropout): super(dgmslice_ps, self).__init__() self.filters = ef_num_filters self.pslevel = pslevel self.siglength = [ iisignature.siglength(num_slices + 1, m) for m in pslevel ] self.eigfs = nn.ModuleList() self.final_vec_length = self.filters * sum(self.siglength) self.slices = num_slices for i in range(self.filters): self.eigfs.append(eigf(ef_num_hlayers, ef_num_hu)) self.projections = nn.Conv1d(1, self.slices, 2, 2) self.final_layer = nn.Sequential(nn.Dropout(dropout), nn.Linear(self.final_vec_length, 1), nn.BatchNorm1d(1))
def ComputeMultiLevelSig1dBM(BM_paths, number_of_segment, depth_of_tensors, T): """ Compute the signature of all samples """ s = iisignature.prepare(2, depth_of_tensors) no_of_samples = np.shape(BM_paths)[0] MultiLevelSigs = np.zeros([no_of_samples, iisignature.siglength( 2, depth_of_tensors) * number_of_segment - 1], dtype=float) print('start computing the sigs of degree %d:' % depth_of_tensors) for j in tqdm(range(0, no_of_samples, 1), total=no_of_samples): BM = TimeJointPath(BM_paths[j, :], T) result2 = ComputeMultiLevelSig( BM, number_of_segment, depth_of_tensors, s, sig='True') MultiLevelSigs[j] = result2['MultiLevelLogSig'] if number_of_segment > 1: n_input = int(np.shape(MultiLevelSigs)[1] / number_of_segment) X_sig = MultiLevelSigs.reshape( (np.shape(MultiLevelSigs)[0], number_of_segment, n_input)) else: X_sig = MultiLevelSigs return X_sig
def __init__(self, n_units, sig_level=2, train_time_lapse =False, initial_time_lapse=0.1, output_signatures = False,#whether the output includes the signatures use_signatures = True, #whether each new state can depend on the signature kernel_initializer='glorot_uniform', recurrent_initializer='he_normal',#could be good to use 'orthogonal' if not use_signatures activation='tanh',#not applied to signature elements **kwargs): self.sig_level = sig_level self.sigsize = iisignature.siglength(2,sig_level) self.n_units = n_units #like output_dim self.units = n_units*(self.sigsize+1) if output_signatures else n_units self.train_time_lapse = train_time_lapse self.initial_time_lapse = initial_time_lapse self.output_signatures = output_signatures self.use_signatures = use_signatures self.kernel_initializer = initializers.get(kernel_initializer) self.recurrent_initializer = initializers.get(recurrent_initializer) self.activation = activations.get(activation) super(RecurrentSig, self).__init__(**kwargs)
def test_batch(self): numpy.random.seed(734) d=2 m=2 n=15 paths = [numpy.random.uniform(-1,1,size=(6,d)) for i in range(n)] pathArray15=stack(paths) pathArray1315=numpy.reshape(pathArray15,(1,3,1,5,6,d)) sigs = [iisignature.sig(i,m) for i in paths] sigArray=stack(sigs) sigArray15=iisignature.sig(pathArray15,m) sigArray1315=iisignature.sig(pathArray1315,m) siglength=iisignature.siglength(d,m) self.assertEqual(sigArray1315.shape,(1,3,1,5,siglength)) self.assertTrue(numpy.allclose(sigArray1315.reshape(n,siglength),sigs)) self.assertEqual(sigArray15.shape,(15,siglength)) self.assertTrue(numpy.allclose(sigArray15,sigs)) backsigs=[iisignature.sigbackprop(i,j,m) for i,j in zip(sigs,paths)] backsigArray = stack(backsigs) backsigs1315=iisignature.sigbackprop(sigArray1315,pathArray1315,m) self.assertEqual(backsigs1315.shape,(1,3,1,5,6,d)) self.assertTrue(numpy.allclose(backsigs1315.reshape(n,6,2),backsigArray)) data=[numpy.random.uniform(size=(d,)) for i in range(n)] dataArray1315=stack(data).reshape((1,3,1,5,d)) joined=[iisignature.sigjoin(i,j,m) for i,j in zip(sigs,data)] joined1315=iisignature.sigjoin(sigArray1315,dataArray1315,m) self.assertEqual(joined1315.shape,(1,3,1,5,siglength)) self.assertTrue(numpy.allclose(joined1315.reshape(n,-1),stack(joined))) backjoined=[iisignature.sigjoinbackprop(i,j,k,m) for i,j,k in zip(joined,sigs,data)] backjoinedArrays=[stack([i[j] for i in backjoined]) for j in range(2)] backjoined1315=iisignature.sigjoinbackprop(joined1315,sigArray1315,dataArray1315,m) self.assertEqual(backjoined1315[0].shape,sigArray1315.shape) self.assertEqual(backjoined1315[1].shape,dataArray1315.shape) self.assertTrue(numpy.allclose(backjoined1315[0].reshape(n,-1),backjoinedArrays[0])) self.assertTrue(numpy.allclose(backjoined1315[1].reshape(n,-1),backjoinedArrays[1])) scaled=[iisignature.sigscale(i,j,m) for i,j in zip(sigs,data)] scaled1315=iisignature.sigscale(sigArray1315,dataArray1315,m) self.assertEqual(scaled1315.shape,(1,3,1,5,siglength)) self.assertTrue(numpy.allclose(scaled1315.reshape(n,-1),stack(scaled))) backscaled=[iisignature.sigscalebackprop(i,j,k,m) for i,j,k in zip(scaled,sigs,data)] backscaledArrays=[stack([i[j] for i in backscaled]) for j in range(2)] backscaled1315=iisignature.sigscalebackprop(scaled1315,sigArray1315,dataArray1315,m) self.assertEqual(backscaled1315[0].shape,sigArray1315.shape) self.assertEqual(backscaled1315[1].shape,dataArray1315.shape) self.assertTrue(numpy.allclose(backscaled1315[0].reshape(n,-1),backscaledArrays[0])) self.assertTrue(numpy.allclose(backscaled1315[1].reshape(n,-1),backscaledArrays[1])) s_s=(iisignature.prepare(d,m,"cosax"),iisignature.prepare(d,m,"cosahx")) for type in ("c","o","s","x","a","ch","oh","sh","ah"): s=s_s[1 if "h" in type else 0] logsigs = [iisignature.logsig(i,s,type) for i in paths] logsigArray=stack(logsigs) logsigArray1315=iisignature.logsig(pathArray1315,s,type) self.assertEqual(logsigArray1315.shape,(1,3,1,5,logsigs[0].shape[0]),type) self.assertTrue(numpy.allclose(logsigArray1315.reshape(n,-1),logsigArray),type) if type in ("s","x","sh"): backlogs = stack(iisignature.logsigbackprop(i,j,s,type) for i,j in zip(logsigs,paths)) backlogs1315 = iisignature.logsigbackprop(logsigArray1315,pathArray1315,s,type) self.assertEqual(backlogs1315.shape,backsigs1315.shape) self.assertTrue(numpy.allclose(backlogs1315.reshape(n,6,d),backlogs),type) a=iisignature.rotinv2dprepare(m,"a") rots=stack([iisignature.rotinv2d(i,a) for i in paths]) rots1315=iisignature.rotinv2d(pathArray1315,a) self.assertEqual(rots1315.shape,(1,3,1,5,rots.shape[1])) self.assertTrue(numpy.allclose(rots1315.reshape(n,-1),rots))
def dotest(self,type): m = 8 nPaths = 95 nAngles = 348 numpy.random.seed(775) s = iisignature.rotinv2dprepare(m,type) coeffs = iisignature.rotinv2dcoeffs(s) angles = numpy.random.uniform(0,math.pi * 2,size=nAngles + 1) angles[0] = 0 rotationMatrices = [numpy.array([[math.cos(i),math.sin(i)],[-math.sin(i),math.cos(i)]]) for i in angles] paths = [numpy.random.uniform(-1,1,size=(32,2)) for i in range(nPaths)] samePathRotInvs = [iisignature.rotinv2d(numpy.dot(paths[0],mtx),s) for mtx in rotationMatrices] #check the length matches (length,) = samePathRotInvs[0].shape self.assertEqual(length,sum(i.shape[0] for i in coeffs)) self.assertEqual(length,iisignature.rotinv2dlength(s)) if type == "a": self.assertEqual(length,sumCentralBinomialCoefficient(m // 2)) self.assertLess(length,nAngles)#sanity check on the test itself #check that the invariants are invariant if 0: print("\n",numpy.column_stack(samePathRotInvs[0:7])) for i in range(nAngles): if 0 and diff(samePathRotInvs[0],samePathRotInvs[1 + i]) > 0.01: print(i) print(samePathRotInvs[0] - samePathRotInvs[1 + i]) print(diff(samePathRotInvs[0],samePathRotInvs[1 + i])) self.assertLess(diff(samePathRotInvs[0],samePathRotInvs[1 + i]),0.01) #check that the invariants match the coefficients if 1: sigLevel=iisignature.sig(paths[0],m)[iisignature.siglength(2,m-1):] lowerRotinvs = 0 if 2==m else iisignature.rotinv2dlength(iisignature.rotinv2dprepare(m-2,type)) #print("\n",numpy.dot(coeffs[-1],sigLevel),"\n",samePathRotInvs[0][lowerRotinvs:]) #print(numpy.dot(coeffs[-1],sigLevel)-samePathRotInvs[0][lowerRotinvs:]) self.assertTrue(numpy.allclose(numpy.dot(coeffs[-1],sigLevel),samePathRotInvs[0][lowerRotinvs:],atol=0.000001)) #check that we are not missing invariants if type == "a": #print("\nrotinvlength=",length," #siglength=",iisignature.siglength(2,m)) sigOffsets = [] for path in paths: samePathSigs = [iisignature.sig(numpy.dot(path,mtx),m) for mtx in rotationMatrices[1:70]] samePathSigsOffsets = [i - samePathSigs[0] for i in samePathSigs[1:]] sigOffsets.extend(samePathSigsOffsets) #print(numpy.linalg.svd(numpy.row_stack(sigOffsets))[1]) def split(a, dim, level): start = 0 out = [] for m in range(1,level + 1): levelLength = dim ** m out.append(a[:,start:(start + levelLength)]) start = start + levelLength assert(start == a.shape[1]) return out allOffsets = numpy.row_stack(sigOffsets) #print (allOffsets.shape) splits = split(allOffsets,2,m) #print() rank_tolerance = 0.01 # this is hackish #print #([numpy.linalg.matrix_rank(i.astype("float64"),rank_tolerance) #for #i in splits]) #print ([i.shape for i in splits]) #print(numpy.linalg.svd(splits[-1])[1]) #sanity check on the test self.assertLess(splits[-1].shape[1],splits[0].shape[0]) totalUnspannedDimensions = sum(i.shape[1] - numpy.linalg.matrix_rank(i,rank_tolerance) for i in splits) self.assertEqual(totalUnspannedDimensions,length) if 0: #This doesn't work - the rank of the whole thing is less than #sigLength-totalUnspannedDimensions, which suggests that there are #inter-level dependencies, #even though the shuffle product dependencies aren't linear. #I don't know why this is. sigLength = iisignature.siglength(2,m) numNonInvariant = numpy.linalg.matrix_rank(numpy.row_stack(sigOffsets)) predictedNumberInvariant = sigLength - numNonInvariant print(sigLength,length,numNonInvariant) self.assertLess(sigLength,nAngles) self.assertEqual(predictedNumberInvariant,length)
def sigdim(d,m): return 1 + iisignature.siglength(d,m)
def perform(self,node,inp,out): #do I really need to create an array here? out[0][0]=np.array(iisignature.siglength(inp[0],inp[1]),dtype="int32")
fixed = 0.1 numpy.random.seed(51) start = numpy.random.uniform(size=(pathlength, dim)).astype("float32") #2: DEFINE THEANO STUFF path = theano.shared(start, "path") if not numpy.isnan(fixed): fixedT = theano.shared(fixed, "fixedT") path = theano.tensor.horizontal_stack( path[:, :-1], fixedT * T.shape_padright(T.arange(pathlength))) cost1 = theano.tensor.mean(theano.tensor.sqr(Sig(path, level))) grad1 = theano.grad(cost1, path) signature = numpy.zeros((1, iisignature.siglength(dim, level))).astype("float32") for i in six.moves.xrange(1, pathlength): if not numpy.isnan(fixed): displacement = path[i:(i + 1), :-1] - path[(i - 1):i, :-1] signature = SigJoin(signature, displacement, level, fixedT) else: displacement = path[i:(i + 1), :] - path[(i - 1):i, :] signature = SigJoin(signature, displacement, level) cost2 = theano.tensor.mean(theano.tensor.sqr(signature)) grad2 = theano.grad(cost2, path) #theano.printing.pydotprint(grad2,outfile="a.png") ff = theano.function([], [grad1, grad2]) #theano.printing.pydotprint(ff,outfile="b.png")
def setup(obj): obj.path = torch.rand(obj.size, dtype=torch.float).numpy() shape = obj.size[-3], iisignature.siglength(obj.size[-1], obj.depth) obj.grad = torch.rand(shape).numpy()
#This program just continually runs some of the important functionality in #iisignature on small data, so that you can check that memory usage #does not grow. Even a tiny memory leak becomes very visible e.g. in htop. #add the parent directory, so we find our iisignature build if it was built --inplace sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) import iisignature length = 20 dim=3 level=2 npaths=3 paths_ = np.random.uniform(size=(npaths,length,dim)) scale_ = np.random.uniform(size=(npaths,dim)) initialsigs_ = np.random.uniform(size=(npaths,iisignature.siglength(dim,level))) p=iisignature.prepare(dim,level,"cosx") while 0: iisignature.sig(paths[0],level) for i in range(10**10): #copy major parts of the input data, in case we are leaking references to it paths=paths_[:] increment=scale=scale_[:] initialsigs=initialsigs_[:] iisignature.sigjoin(initialsigs,scale,level) iisignature.sigscale(initialsigs,scale,level) iisignature.sigjoinbackprop(initialsigs,initialsigs,scale,level) iisignature.sigscalebackprop(initialsigs,initialsigs,scale,level) iisignature.sig(paths[0,:,:],level) iisignature.sigbackprop(initialsigs[0,:],paths[0,:,:],level) #iisignature.sigjacobian(paths[0,:,:],level)
def test_batch(self): numpy.random.seed(734) d=2 m=2 n=15 paths = [numpy.random.uniform(-1,1,size=(6,d)) for i in range(n)] pathArray15=stack(paths) pathArray1315=numpy.reshape(pathArray15,(1,3,1,5,6,d)) sigs = [iisignature.sig(i,m) for i in paths] sigArray=stack(sigs) sigArray15=iisignature.sig(pathArray15,m) sigArray1315=iisignature.sig(pathArray1315,m) siglength=iisignature.siglength(d,m) self.assertEqual(sigArray1315.shape,(1,3,1,5,siglength)) self.assertTrue(numpy.allclose(sigArray1315.reshape(n,siglength),sigs)) self.assertEqual(sigArray15.shape,(15,siglength)) self.assertTrue(numpy.allclose(sigArray15,sigs)) backsigs=[iisignature.sigbackprop(i,j,m) for i,j in zip(sigs,paths)] backsigArray = stack(backsigs) backsigs1315=iisignature.sigbackprop(sigArray1315,pathArray1315,m) self.assertEqual(backsigs1315.shape,(1,3,1,5,6,d)) self.assertTrue(numpy.allclose(backsigs1315.reshape(n,6,2),backsigArray)) data=[numpy.random.uniform(size=(d,)) for i in range(n)] dataArray1315=stack(data).reshape((1,3,1,5,d)) joined=[iisignature.sigjoin(i,j,m) for i,j in zip(sigs,data)] joined1315=iisignature.sigjoin(sigArray1315,dataArray1315,m) self.assertEqual(joined1315.shape,(1,3,1,5,siglength)) self.assertTrue(numpy.allclose(joined1315.reshape(n,-1),stack(joined))) backjoined=[iisignature.sigjoinbackprop(i,j,k,m) for i,j,k in zip(joined,sigs,data)] backjoinedArrays=[stack([i[j] for i in backjoined]) for j in range(2)] backjoined1315=iisignature.sigjoinbackprop(joined1315,sigArray1315,dataArray1315,m) self.assertEqual(backjoined1315[0].shape,sigArray1315.shape) self.assertEqual(backjoined1315[1].shape,dataArray1315.shape) self.assertTrue(numpy.allclose(backjoined1315[0].reshape(n,-1),backjoinedArrays[0])) self.assertTrue(numpy.allclose(backjoined1315[1].reshape(n,-1),backjoinedArrays[1])) dataAsSigs=[iisignature.sig(numpy.row_stack([numpy.zeros((d,)),i]),m) for i in data] dataArray13151=dataArray1315[:,:,:,:,None,:] dataArray13151=numpy.repeat(dataArray13151,2,4)*[[0.0],[1.0]] dataArrayAsSigs1315=iisignature.sig(dataArray13151,m) combined1315=iisignature.sigcombine(sigArray1315,dataArrayAsSigs1315,d,m) self.assertEqual(joined1315.shape,combined1315.shape) self.assertTrue(numpy.allclose(joined1315,combined1315)) backcombined1315=iisignature.sigcombinebackprop(joined1315,sigArray1315,dataArrayAsSigs1315,d,m) backcombined=[iisignature.sigcombinebackprop(i,j,k,d,m) for i,j,k in zip(joined,sigs,dataAsSigs)] backcombinedArrays=[stack([i[j] for i in backcombined]) for j in range(2)] self.assertEqual(backcombined1315[0].shape,sigArray1315.shape) self.assertEqual(backcombined1315[1].shape,sigArray1315.shape) self.assertTrue(numpy.allclose(backjoined1315[0],backcombined1315[0])) self.assertTrue(numpy.allclose(backcombined1315[0].reshape(n,-1),backcombinedArrays[0])) self.assertTrue(numpy.allclose(backcombined1315[1].reshape(n,-1),backcombinedArrays[1])) scaled=[iisignature.sigscale(i,j,m) for i,j in zip(sigs,data)] scaled1315=iisignature.sigscale(sigArray1315,dataArray1315,m) self.assertEqual(scaled1315.shape,(1,3,1,5,siglength)) self.assertTrue(numpy.allclose(scaled1315.reshape(n,-1),stack(scaled))) backscaled=[iisignature.sigscalebackprop(i,j,k,m) for i,j,k in zip(scaled,sigs,data)] backscaledArrays=[stack([i[j] for i in backscaled]) for j in range(2)] backscaled1315=iisignature.sigscalebackprop(scaled1315,sigArray1315,dataArray1315,m) self.assertEqual(backscaled1315[0].shape,sigArray1315.shape) self.assertEqual(backscaled1315[1].shape,dataArray1315.shape) self.assertTrue(numpy.allclose(backscaled1315[0].reshape(n,-1),backscaledArrays[0])) self.assertTrue(numpy.allclose(backscaled1315[1].reshape(n,-1),backscaledArrays[1])) s_s=(iisignature.prepare(d,m,"cosax"),iisignature.prepare(d,m,"cosahx")) for type in ("c","o","s","x","a","ch","oh","sh","ah"): s=s_s[1 if "h" in type else 0] logsigs = [iisignature.logsig(i,s,type) for i in paths] logsigArray=stack(logsigs) logsigArray1315=iisignature.logsig(pathArray1315,s,type) self.assertEqual(logsigArray1315.shape,(1,3,1,5,logsigs[0].shape[0]),type) self.assertTrue(numpy.allclose(logsigArray1315.reshape(n,-1),logsigArray),type) if type in ("s","x","sh"): backlogs = stack(iisignature.logsigbackprop(i,j,s,type) for i,j in zip(logsigs,paths)) backlogs1315 = iisignature.logsigbackprop(logsigArray1315,pathArray1315,s,type) self.assertEqual(backlogs1315.shape,backsigs1315.shape) self.assertTrue(numpy.allclose(backlogs1315.reshape(n,6,d),backlogs),type) a=iisignature.rotinv2dprepare(m,"a") rots=stack([iisignature.rotinv2d(i,a) for i in paths]) rots1315=iisignature.rotinv2d(pathArray1315,a) self.assertEqual(rots1315.shape,(1,3,1,5,rots.shape[1])) self.assertTrue(numpy.allclose(rots1315.reshape(n,-1),rots))
def iisignature_sig(x, d): if len(x) <= 1: return np.zeros(iisignature.siglength(x.shape[1], d)) else: return iisignature.sig(x, d)
import os, sys #os.environ["KERAS_BACKEND"]="tensorflow" #os.environ["THEANO_FLAGS"]="mode=DebugMode,device=cpu,optimizer_excluding=local_shape_to_shape_i" import numpy as np, keras import keras.models, keras.layers.recurrent, keras.layers.core import keras.backend as K sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) if K.backend() == "theano": from iisignature_theano import Sig if K.backend() == "tensorflow": from iisignature_tensorflow import Sig import iisignature sig_level = 2 siglen = iisignature.siglength(2, sig_level) nSamples = 21 xDim = 55 X = np.zeros((nSamples, xDim), dtype="float32") Y = np.ones((nSamples, ), dtype="float32") m = keras.models.Sequential() m.add(keras.layers.core.Dense(106, input_shape=(xDim, ))) m.add(keras.layers.core.Reshape((53, 2))) m.add(keras.layers.core.Lambda(lambda x: Sig(x, 2), output_shape=(siglen, ))) m.add(keras.layers.core.Reshape((siglen, 1))) m.add(keras.layers.pooling.AveragePooling1D(siglen)) m.add(keras.layers.core.Flatten()) m.compile(loss='mse', optimizer="sgd")
import os, sys #os.environ["KERAS_BACKEND"]="tensorflow" #os.environ["THEANO_FLAGS"]="mode=DebugMode,device=cpu,optimizer_excluding=local_shape_to_shape_i" import numpy as np, keras import keras.models, keras.layers.recurrent, keras.layers.core import keras.backend as K sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) if K.backend() == "theano": from iisignature_theano import Sig if K.backend() == "tensorflow": from iisignature_tensorflow import Sig import iisignature sig_level=2 siglen = iisignature.siglength(2,sig_level) nSamples=21 xDim=55 X=np.zeros((nSamples,xDim),dtype="float32") Y=np.ones((nSamples,),dtype="float32") m=keras.models.Sequential() m.add(keras.layers.core.Dense(106, input_shape=(xDim,))) m.add(keras.layers.core.Reshape((53,2))) m.add(keras.layers.core.Lambda(lambda x:Sig(x,2),output_shape=(siglen,))) m.add(keras.layers.core.Reshape((siglen,1))) m.add(keras.layers.pooling.AveragePooling1D(siglen)) m.add(keras.layers.core.Flatten()) m.compile(loss='mse',optimizer="sgd")
#This program just continually runs some of the important functionality in #iisignature on small data, so that you can check that memory usage #does not grow. Even a tiny memory leak becomes very visible e.g. in htop. #add the parent directory, so we find our iisignature build if it was built --inplace sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(__file__)))) import iisignature length = 20 dim = 3 level = 2 npaths = 3 paths_ = np.random.uniform(size=(npaths, length, dim)) scale_ = np.random.uniform(size=(npaths, dim)) initialsigs_ = np.random.uniform(size=(npaths, iisignature.siglength(dim, level))) p = iisignature.prepare(dim, level, "cosx") while 0: iisignature.sig(paths[0], level) for i in range(10**10): #copy major parts of the input data, in case we are leaking references to it paths = paths_[:] increment = scale = scale_[:] initialsigs = initialsigs_[:] iisignature.sigjoin(initialsigs, scale, level) iisignature.sigscale(initialsigs, scale, level) iisignature.sigjoinbackprop(initialsigs, initialsigs, scale, level) iisignature.sigscalebackprop(initialsigs, initialsigs, scale, level) iisignature.sig(paths[0, :, :], level) iisignature.sigbackprop(initialsigs[0, :], paths[0, :, :], level) #iisignature.sigjacobian(paths[0,:,:],level)
def perform(self,node,inp,out): #do I really need to create an array here? out[0][0]=numpy.array(iisignature.siglength(inp[0],inp[1]),dtype="int32")
def sigdim(d, m): return 1 + iisignature.siglength(d, m)
fixed = float("nan") fixed = 0.1 numpy.random.seed(51) start = numpy.random.uniform(size=(pathlength,dim)).astype("float32") #2: DEFINE THEANO STUFF path = theano.shared(start, "path") if not numpy.isnan(fixed): fixedT = theano.shared(fixed, "fixedT") path=theano.tensor.horizontal_stack(path[:,:-1],fixedT*T.shape_padright(T.arange(pathlength))) cost1 = theano.tensor.mean(theano.tensor.sqr(Sig(path,level))) grad1 = theano.grad(cost1,path) signature = numpy.zeros((1,iisignature.siglength(dim,level))).astype("float32") for i in six.moves.xrange(1,pathlength): if not numpy.isnan(fixed): displacement = path[i:(i+1),:-1]-path[(i-1):i,:-1] signature = SigJoin(signature,displacement,level,fixedT) else: displacement = path[i:(i+1),:]-path[(i-1):i,:] signature = SigJoin(signature,displacement,level) cost2 = theano.tensor.mean(theano.tensor.sqr(signature)) grad2 = theano.grad(cost2,path) #theano.printing.pydotprint(grad2,outfile="a.png") ff = theano.function([],[grad1,grad2]) #theano.printing.pydotprint(ff,outfile="b.png")