def match_parameters(p, q, method="munkres", discard_misses=False): """ Match two sets of parameters. TODO: finish greedy """ logger.info("Matching with method %s" % method) assert p.shape[1] == q.shape[1], ( "Shapes do not match (%s vs %s)" % (p.shape, q.shape) ) match_size = min(p.shape[0], q.shape[0]) corrs = np.corrcoef(p, q)[match_size:, :match_size] corrs[np.isnan(corrs)] = 0 if method == "munkres": m = Munkres() cl = 1 - np.abs(corrs) if (cl.shape[0] > cl.shape[1]): indices = m.compute(cl.T) else: indices = m.compute(cl) indices = [(i[1], i[0]) for i in indices] elif method == "greedy": q_idx = [] raise NotImplementedError("Greedy not supported yet.") for c in range(q.shape[0]): idx = corrs[c, :].argmax() q_idx.append(idx) corrs[:,idx] = 0 else: raise NotImplementedError("%s matching not supported" % method) return indices
def Objmatch(objy,objx,ref,refc,L,W,im,length): global D_limit_s dmtx = np.zeros((L,W)) cmtx = np.zeros((L,W)) Wd = 0.5 #weight of distance Wc = 1-Wd #weight of color for i in range(L): dmtx[i,:] =((objy - ref[i][0])**2+(objx - ref[i][1])**2).T cmtx[i,:] = Color_Dif(im,objx,objy,refc[i],length[i]) dmtx = dmtx/diag # normalize the distance by divid diag dmtx[dmtx>D_limit_s] = 10**6 cmtx = cmtx*Wc + dmtx*Wd tmp = copy.deepcopy(cmtx) m = Munkres() if L<=W: indexes = m.compute(cmtx) else: # len(ori) > # live_blobs indexes = m.compute(cmtx.T) indexes = [(s[1],s[0]) for s in indexes] D_idx = [] if vid_idx>=0: for i in range(len(indexes))[::-1]: if tmp[indexes[i][0],indexes[i][1]]>10**5: D_idx.append(i) indexes.pop(i) return indexes,D_idx
def fixColouringAndCompare(atk, btk): """ 15 April 2013 input: atk, btk are clustering results output: btk['pattern'] and btk['centroids'][1] fixed returning the distanceSquaredMatrix and the indices """ k = len(atk["centroids"][0]) # k = a.k aClusters = [-999] * k # initialising a length-k list for convenience bClusters = [-999] * k for i in range(k): # x-coord, y-coord, weight of the i-th cluster in a aClusters[i] = { "x": atk["centroids"][0][i][0], "y": atk["centroids"][0][i][1], "weight": len([v for v in atk["centroids"][1] if v == i]), } # doing the same for b bClusters[i] = { "x": btk["centroids"][0][i][0], "y": btk["centroids"][0][i][1], "weight": len([v for v in btk["centroids"][1] if v == i]), } distanceSquaredMatrix = np.ones((k, k)) * (-999.0) for i in range(k): for j in range(k): dist2 = (aClusters[i]["x"] - bClusters[j]["x"]) ** 2 + (aClusters[i]["y"] - bClusters[j]["y"]) ** 2 # print i,j, dist2 #debug distanceSquaredMatrix[i, j] = dist2 from munkres import Munkres m = Munkres() indices = m.compute(distanceSquaredMatrix.copy()) # munkres would alter the entries # indicies2=dict([(v[1], v[0]) for v in indices]) indices2 = m.compute(distanceSquaredMatrix.copy().T) # munkres would alter the entries indices2Dict = dict(indices2) # print indices2 #debug # print indices2Dict bData = btk["data"] bCentroids = btk["centroids"] for i in range(len(bCentroids[1])): newColour = indices2Dict[bCentroids[1][i]] btk["centroids"][1][i] = newColour btk["pattern"].matrix[bData[i][1], bData[i][0]] = newColour abCompare = { "distanceSquared": distanceSquaredMatrix, "indices": indices, "aClusters": aClusters, "bClusters": bClusters, } return abCompare
def similar(list_current,list_called): global P,total # comparing the length of two files to compare smaller length to bigger if len(list_current)<len(list_called): # calling comparison function to compare both files line by line for similarity similarity = comparison(list_current,list_called) # storing the lenght of smaller P = len(list_current) point=[[0 for x in range(len(list_called))] for y in range(len(list_current))] else: # calling comparison function to compare both files line by line for similarity similarity = comparison(list_called,list_current) P = len(list_called) point=[[0 for x in range(len(list_current))] for y in range(len(list_called))] # calling functions of munkres to form maximum weighted bipartite matching graph graph_matrix = make_cost_matrix(similarity, lambda cost: 1.0 - cost) m = Munkres() indexes =m.compute(graph_matrix) total = 0 for row, column in indexes: # forming list of points(lines) of similarity between two files value = similarity[row][column] if value>0.0: total += 1 point[row][column]=1 return point
def hun(costMatrix): # Check first, if costmatrix is not empty if costMatrix.shape==(0,0): return [] # Create squared temporary matrix tmpMatrix = numpy.copy(costMatrix) tmpMatrix = makeSquareWithNegValues(tmpMatrix) sqCostMatrix = numpy.copy(tmpMatrix) sqCostMatrix[tmpMatrix==-1]=10e10 # Solve ASP on the temporary matrix m=Munkres() i=m.compute(sqCostMatrix) # Create resultin matrix that contains ones at matching # objects and remove all excluded matches binMatrix = numpy.zeros( tmpMatrix.shape,dtype=bool ) for x,y in i: if tmpMatrix[x,y]==-1: continue binMatrix[x,y]=True return binMatrix
def __assign_labels_to_clusters__(assignment, labels, clusters, clusts_labels): cost_matrix = gen_assignment_cost_matrix(assignment, labels, clusters, clusts_labels) munkres = Munkres() assignment_list = munkres.compute(cost_matrix) # assignment_list = [(i,i) for i in xrange(len(clusters))] #for debugging assigned_clusts_labels = dict(assignment_list) # dictionary {cluster_no: assigned_label_no} return assigned_clusts_labels
def closest_permuted_matrix( A, B ): """Find a _row_ permutation of B that matches A most closely (i.e. min |A - B|_F)""" # The rows of A and B form a weighted bipartite graph. The weights # are computed using the vector_matching algorithm. # We need to find their minimal matching. assert( A.shape == B.shape ) n, _ = A.shape m = Munkres() # Create the weight matrix W = sc.zeros( (n, n) ) for i in xrange( n ): for j in xrange( n ): # Best matching between A and B W[i, j] = norm(A[i] - B[j]) matching = m.compute( W ) matching.sort() _, rowp = zip(*matching) rowp = array( rowp ) # Permute the rows of B according to Bi B_ = B[ rowp ] return B_
def match(self, model_manager): individuals = model_manager.individuals groups = model_manager.groups pref_matrix = [] individual_count = len(individuals) row_index = -1 individuals_by_row = {} groups_by_col = {} for individual_id, individual in individuals.iteritems(): row_index += 1 individuals_by_row[str(row_index)] = individual pref_matrix_row = [] col_index = -1 for group_id, group in groups.iteritems(): group_pref_value = individual.get_group_pref_value(group.id) # we use group slots to control the max number of individuals per group. one individual per slot # each slot represents a potential membership within a group within the preference matrix. # the len(pref_matrix_group_slots[grounp.id]) == min(group.max_size, len(individuals)) group_slot_size = min(group.max_size, individual_count) for s in range(group_slot_size): # multiply value by negative 1 because munkres finds # the assignment with minimum net value, # and we want to find the assignment with # maximum net value pref_matrix_row.append(group_pref_value * -1) col_index += 1 groups_by_col[str(col_index)] = group pref_matrix.append(pref_matrix_row) munkres = Munkres() optimal_match_indexes = munkres.compute(pref_matrix) assignments = [(individuals_by_row[str(row)], groups_by_col[str(col)]) for row, col in optimal_match_indexes] return assignments
def fix_parameters(true, guess, weights): """Find a column permutation of guess parameters that matches true parameters most closely (i.e. min |A - B|_F) also apply this to weights""" # The rows of A and B form a weighted bipartite graph. The weights # are computed using the vector_matching algorithm. # We need to find their minimal matching. assert true.shape == guess.shape d, k = true.shape m = Munkres() # Create the weight matrix W = sc.zeros((k, k)) for i in xrange(k): for j in xrange(k): # Best matching between A and B W[i, j] = norm(true.T[i] - guess.T[j]) matching = m.compute(W) matching.sort() _, colp = zip(*matching) colp = array(colp) # Permute the rows of B according to Bi guess = guess[:, colp] weights = weights[colp] return weights, guess
def do_matching(gsrEvents, warnings): matrix = [] M = len(gsrEvents) N = len(warnings) for m in range(M): row = [] gsr = gsrEvents[m] for n in range(N): warn = warnings[n] if match(gsr, warn): row.append(get_quality(gsr, warn)) else: row.append(.0) matrix.append(row) costMatrix = [] #create the cost matrix for m in range(M): r = [] gsr = gsrEvents[m] for n in range(N): warn = warnings[n] r.append(10 - matrix[m][n]) costMatrix.append(r) m = Munkres() if M > 0 and N > 0: indexes = m.compute(costMatrix) else: return None, None return matrix, indexes
def loss1(usersPerCircle, usersPerCircleP): #psize: either the number of groundtruth, or the number of predicted circles (whichever is larger) psize = max(len(usersPerCircle),len(usersPerCircleP)) # Pad the matrix to be square # mm: matching matrix containing costs of matching groundtruth circles to predicted circles. # mm[i][j] = cost of matching groundtruth circle i to predicted circle j mm = numpy.zeros((psize,psize)) # mm2: copy of mm since the Munkres library destroys the data during computation mm2 = numpy.zeros((psize,psize)) for i in range(psize): for j in range(psize): circleP = set() # Match to an empty circle (delete all users) circle = set() # Match to an empty circle (add all users) if (i < len(usersPerCircleP)): circleP = usersPerCircleP[i] if (j < len(usersPerCircle)): circle = usersPerCircle[j] nedits = len(circle.union(circleP)) - len(circle.intersection(circleP)) # Compute the edit distance between the two circles mm[i][j] = nedits mm2[i][j] = nedits if psize == 0: return 0 # Edge case in case there are no circles else: m = Munkres() #print mm2 # Print the pairwise cost matrix indices = m.compute(mm) # Compute the optimal alignment between predicted and groundtruth circles editCost = 0 for row, column in indices: #print row,column # Print the optimal value selected by matching editCost += mm2[row][column] return int(editCost)
class HungarianMapper(BaseMapper): def __init__(self, cost=None): super(HungarianMapper, self).__init__(cost=cost) self._munkres = Munkres() def __call__(self, A, B): # Cooccurrence matrix matrix = self.cost(A, B) # Shape and labels nRows, nCols = matrix.shape rows = matrix.get_rows() cols = matrix.get_columns() # Cost matrix N = max(nCols, nRows) C = np.zeros((N, N)) C[:nCols, :nRows] = (np.max(matrix.df.values) - matrix.df.values).T mapping = {} for b, a in self._munkres.compute(C): if (b < nCols) and (a < nRows): if matrix[rows[a], cols[b]] > 0: mapping[rows[a]] = cols[b] return mapping
def getFileSim(fileA,fileB,alpha,beta): #to find the similarity of two files File1=open(dirname+'/'+fileA, "r") File2=open(dirname+'/'+fileB, "r") content1=File1.readlines() flag=0 content2=File2.readlines() if len(content1) > len(content2): flag=1 content1,content2 = content2,content1 sim=[] for sen_A in content1: temp = [] sen_A = sen_A.lower() for sen_B in content2: sen_B = sen_B.lower() temp.append(senSim(sen_A,sen_B,alpha)) sim.append(temp) for i in range(len(sim)) #to make it a maximum cost problem for j in range(len(sim[i])): sim[i][j] = 1.0-sim[i][j] m=Munkres() result_matrix=m.compute(sim) #implementing hungarian maxSimMatrix = [] for row,column in result_matrix: if sim[row][column]!=1.0: if flag==1: row,column=column,row maxSimMatrix.append([row,column]) #storing which lines are matched FileSim=float(len(maxSimMatrix))/(len(content1)) if FileSim<beta: FileSim = 0 return (FileSim, maxSimMatrix)
def __init__(self, G1, G2, nattr='weight', eattr='weight', lamb = 0.5): G1, G2 = sorted([G1, G2], key=lambda x: len(x)) csim = gs.tacsim_combined_in_C(G1, G2, node_attribute=nattr, edge_attribute=eattr, lamb=lamb) self.csim = csim / np.sqrt(((csim * csim).sum())) # to ensure valid structural distance self.g1 = G1 self.g2 = G2 m = Munkres() cdist = (1 - self.csim).tolist() self.matching = m.compute(cdist) nmap = {} def _gen_nnid(node): if node not in nmap: nmap[node] = len(nmap) return nmap[node] self.mesos = nx.DiGraph() for (e1_idx, e2_idx) in self.matching: e1 = G1.edges()[e1_idx] e2 = G2.edges()[e2_idx] ns = _gen_nnid(e1[0]) nt = _gen_nnid(e1[1]) self.mesos.add_edge(ns, nt) self.mesos.edge[ns][nt][eattr] = 0.5 * (G1.edge[e1[0]][e1[1]][eattr] + G2.edge[e2[0]][e2[1]][eattr]) self.mesos.node[ns][nattr] = 0.5 * (G1.node[e1[0]][nattr] + G2.node[e2[0]][nattr]) self.mesos.node[nt][nattr] = 0.5 * (G1.node[e1[1]][nattr] + G2.node[e2[1]][nattr])
def eval_result(labels, result_gen, cache_file): if path.exists(cache_file): print "Loading cached result..." with open(cache_file, "rb") as inf: lbl_clst = pickle.load(inf) print "Done." else: lbl_clst = result_gen() print "Saving result to cache..." with open(cache_file, "wb") as outf: pickle.dump(lbl_clst, outf) print "Done." all_langs = ["da", "de", "el", "en", "es", "fi", "fr", "it", "nl", "pt", "sv"] print "Constructing cost matrix..." nObj = len(labels) nLang = len(all_langs) G = [[0 for j in range(nLang)] for i in range(nLang)] for i in range(nLang): for j in range(nLang): G[i][j] = -sum([(lbl_clst[k] == i and labels[k] == all_langs[j]) for k in range(nObj)]) print "Finding best mapping..." m = Munkres() idx = m.compute(G) print "Calculating accuracy..." total = 0 for row, col in idx: total += G[row][col] accuracy = -total / float(nObj) print "Accuracy = %.4f" % accuracy
def p345(): A = [[ 7, 53, 183, 439, 863, 497, 383, 563, 79, 973, 287, 63, 343, 169, 583], [627, 343, 773, 959, 943, 767, 473, 103, 699, 303, 957, 703, 583, 639, 913], [447, 283, 463, 29, 23, 487, 463, 993, 119, 883, 327, 493, 423, 159, 743], [217, 623, 3, 399, 853, 407, 103, 983, 89, 463, 290, 516, 212, 462, 350], [960, 376, 682, 962, 300, 780, 486, 502, 912, 800, 250, 346, 172, 812, 350], [870, 456, 192, 162, 593, 473, 915, 45, 989, 873, 823, 965, 425, 329, 803], [973, 965, 905, 919, 133, 673, 665, 235, 509, 613, 673, 815, 165, 992, 326], [322, 148, 972, 962, 286, 255, 941, 541, 265, 323, 925, 281, 601, 95, 973], [445, 721, 11, 525, 473, 65, 511, 164, 138, 672, 18, 428, 154, 448, 848], [414, 456, 310, 312, 798, 104, 566, 520, 302, 248, 694, 976, 430, 392, 198], [184, 829, 373, 181, 631, 101, 969, 613, 840, 740, 778, 458, 284, 760, 390], [821, 461, 843, 513, 17, 901, 711, 993, 293, 157, 274, 94, 192, 156, 574], [ 34, 124, 4, 878, 450, 476, 712, 914, 838, 669, 875, 299, 823, 329, 699], [815, 559, 813, 459, 522, 788, 168, 586, 966, 232, 308, 833, 251, 631, 107], [813, 883, 451, 509, 615, 77, 281, 613, 459, 205, 380, 274, 302, 35, 805]] for r in range(len(A)): for c in range(len(A[0])): A[r][c] *= -1 from munkres import Munkres, print_matrix m = Munkres() indexes = m.compute(A) total = 0 for row, column in indexes: value = A[row][column] total += value return -total
def accuracy(labels_true, labels_pred): labels_true, labels_pred = check_clusterings(labels_true, labels_pred) n_samples = labels_true.shape[0] classes = np.unique(labels_true) clusters = np.unique(labels_pred) # Special limit cases: no clustering since the data is not split; # or trivial clustering where each document is assigned a unique cluster. # These are perfect matches hence return 1.0. if (classes.shape[0] == clusters.shape[0] == 1 or classes.shape[0] == clusters.shape[0] == 0 or classes.shape[0] == clusters.shape[0] == len(labels_true)): return 1.0 # print "accuracy testing..." contingency = contingency_matrix(labels_true, labels_pred) #Type: <type 'numpy.ndarray'>:rows are clusters, cols are classes contingency = -contingency #print contingency contingency = contingency.tolist() m = Munkres() # Best mapping by using Kuhn-Munkres algorithm map_pairs = m.compute(contingency) #best match to find the minimum cost sum_value = 0 for key,value in map_pairs: sum_value = sum_value + contingency[key][value] return float(-sum_value)/n_samples
def maximum_weight_bipartite(matrix): cost_matrix = make_cost_matrix(matrix, lambda cost: 100000 - cost) m = Munkres() indices = m.compute(cost_matrix) return indices
def get_suitability_score(customer_list, product_list): ''' calculate the total maximum suitability score by using munkres algorithm and returns a detailed customer_product_enties & total suitability score ''' suitability_scores = [] customer_suitability_scores = [] for customer in customer_list: for product in product_list: customer_suitability_scores.append(SuitabilityScore.calculate_suitability_score(customer,product)) suitability_scores.append(customer_suitability_scores) customer_suitability_scores = [] customer_product_entries = [] cost_matrix = make_cost_matrix(suitability_scores, lambda cost: 1e10 - cost) munkres = Munkres() indexes = munkres.compute(cost_matrix) total_suitability_score = 0 for customer_index, product_index in indexes: suitability_score = suitability_scores[customer_index][product_index] total_suitability_score += suitability_score suitability_score_entry = SuitabilityScoreEntry(customer_list[customer_index],product_list[product_index],suitability_score) customer_product_entries.append(suitability_score_entry) #print(customer_index,product_index) return customer_product_entries,total_suitability_score
def align(sen1, sen2): """finds the best mapping of words from one sentence to the other""" #find lengths sen1 = list(map(preprocess_word, sen1.split())) sen2 = list(map(preprocess_word, sen2.split())) lengthDif = len(sen1) - len(sen2) if lengthDif > 0: shorter = sen2 longer = sen1 else: shorter = sen1 longer = sen2 lengthDif = abs(lengthDif) shorter += ["emptyWord"] * lengthDif #create matrix matrix = np.zeros((len(longer), len(longer))) for i in range(len(longer)): for j in range(len(longer) - lengthDif): matrix[i,j] = distance.levenshtein(longer[i], shorter[j]) print(matrix) #compare with munkres m = Munkres() indexes = m.compute(matrix) print("mapping is:",[(shorter[i], longer[j]) for (i,j) in indexes])
def match(img_location, features, cluster): img = cv2.imread(img_location) detector = cv2.FeatureDetector_create("SIFT") descriptor = cv2.DescriptorExtractor_create("SIFT") keypoints = detector.detect(img) keypoints = sorted(keypoints, key=lambda x: -x.response) keypoints, img_features = descriptor.compute(img, keypoints[0:5]) img_features = img_features.tolist() m = Munkres() distance = {} for filename in cluster: distance[filename] = 0 fea = features[filename] matrix = [[0 for i in range(5)] for j in range(5)] for i in range(5): for j in range(5): if matrix[j][i] != 0: matrix[i][j] = matrix[j][i] continue try: matrix[i][j] = np.linalg.norm( array(img_features[i]) - array(fea[j]) ) except: matrix[i][j] = 10000 indexes = m.compute(matrix) for row, column in indexes: distance[filename] += matrix[row][column] results = sorted(cluster, key = lambda x: distance[x]) # results = features.keys() return results, distance
def assign_projects(): projects = Project.query.join(Priority).order_by(Project.id).all() users = User.query.join(Priority).order_by(User.id).all() user_ids = [user.id for user in users] default_priority = len(projects) + 1 matrix = [] for project in projects: priority_query = db.session.query(User.id, Priority.priority).\ outerjoin(Priority, db.and_(User.id == Priority.user_id, Priority.project_id == project.id)).\ filter(User.id.in_(user_ids)).\ order_by(User.id).all() priorities = [user_priority_tuple.priority if user_priority_tuple.priority is not None else default_priority for user_priority_tuple in priority_query] matrix.append(priorities) if len(matrix) != 0: db.session.query(Project).update({Project.assignee_id: None}) m = Munkres() indexes = m.compute(matrix) for row, column in indexes: projects[row].assignee_id = user_ids[column] db.session.commit() flash('Project assignments updated.') return redirect(url_for('show_index'))
def main(tutors, players): scores = [] #create cross-scores for tutor in tutors: # create the score array for each tutor to every player scores.append([ getModFLF(tutor, player)*getBaseFLF(tutor,player) for player in players ]) # print the matrix #pretty_print(scores) # find max maxscore = max(max(row) for row in scores) # turn the matrix into a min-problem for row in scores: for idx,col in enumerate(row): row[idx] = maxscore-col # using munkres (copy of tutorial) m = Munkres() indexes = m.compute(scores) # pretty_print(scores) total = 0 print "[[Tutor ::: Player]]" for row, col in indexes: total += scores[row][col] print '{0} ::: {1}'.format(tutors[row],players[col]) print 'total FLF: {0}'.format(maxscore*len(tutors)-total)
def find_ambiguous_mapping(self, res, aa, non_ambiguous_mapping, previous=False): from munkres import Munkres from numpy import fabs, sum, delete total_costs = None mapping = [] ambiguous_keys = [] ambiguous_shifts = [] res_shifts, res_keys = res.get_carbons(previous) aa_shifts, aa_keys = aa.get_carbons() for i, j in non_ambiguous_mapping: if j in aa_keys: k = list(aa_keys).index(j) aa_shifts = delete(aa_shifts, k) aa_keys = delete(aa_keys, k) for i, key in enumerate(res_keys): if self.ambiguous(key, previous): ambiguous_keys.append(key) ambiguous_shifts.append(res_shifts[i]) if len(aa_keys) > 0 and len(ambiguous_shifts) > 0: costs = fabs(subtract.outer(ambiguous_shifts, aa_shifts)) munkres = Munkres() result = munkres.compute(costs * 1.) for i, j in result: mapping.append((ambiguous_keys[i], aa_keys[j])) return mapping
def evaluateFrame(self,X,Y, X_labels=None, Y_labels=None): """ Compute the OSPA metric between two sets of points. """ # check for empty sets if numpy.size(X) == 0 and numpy.size(Y) == 0: return (0,0,0,0) elif numpy.size(X) == 0 or numpy.size(Y) == 0 : return (self.c,0,self.c, 0) # we assume that Y is the larger set m = numpy.size(X,0) n = numpy.size(Y,0) switched = False if m > n: X,Y = Y,X m,n = n,m switched = True dists = self.calculateCostMatrix(X,Y) # Copy cost matrix for munkres module munkres_matrix = numpy.copy(dists) # Only run munkres on non-empty matrix if len(munkres_matrix) > 0: munkres = Munkres() indices = munkres.compute(munkres_matrix) else: indices = [] # compute the OSPA metric total = 0 total_loc = 0 for [i,j] in indices: total_loc += dists[i][j]**self.p # calculate cardinalization error err_cn = (float((self.c)**(self.p)*(n-m))/n)**(1/float(self.p)) # calculate localization error err_loc = (float(total_loc)/n)**(1/float(self.p)) # Not contained in version from github implemented # acc. to paper "A Metric for Performance Evaluation of Multi-Target Tracking Algorithms" # Implementation of labeling error # Penalizes ID switches from frame to frame new_assignments = [] for [i,j] in indices: if (switched): i,j = j,i new_assignments.append((X_labels[i], Y_labels[j])) wrong_labels =len(self.old_assignments) - len(set(new_assignments) & set(self.old_assignments)) rospy.loginfo(wrong_labels) err_label = (float((float(self.a)**float(self.p))/n)*wrong_labels) **(1/float(self.p)) # store current assignments of labels to track self.old_assignments = new_assignments #ospa_err = ( float(total_loc + (n-m)*self.c**self.p) / n)**(1/float(self.p)) ospa_err = ( float(total_loc + self.a*wrong_labels + (n-m)*self.c**self.p) / n)**(1/float(self.p)) ospa_tuple = (ospa_err,err_loc,err_cn, err_label) rospy.loginfo(ospa_tuple) return ospa_tuple
def hungarian_mapping(inames, cnames, target, base): """ Utilizes the hungarian/munkres matching algorithm to compute an initial mapping of inames to cnames. The base cost is the expected correct guesses if each object is matched to itself (i.e., a new object). Then the cost of each object-object match is evaluated by setting each individual object and computing the expected correct guesses. :param inames: the target component names :type inames: collection :param cnames: the base component names :type cnames: collection :param target: An instance or concept.av_counts object to be mapped to the base concept. :type target: :ref:`Instance<instance-rep>` or av_counts obj from concept :param base: A concept to map the target to :type base: TrestleNode :return: a mapping for renaming components in the instance. :rtype: frozenset """ cnames = list(cnames) inames = list(inames) cost_matrix = [] for o in inames: row = [] for c in cnames: nm = {} nm[o] = c cost = mapping_cost({o: c}, target, base) row.append(cost) unmapped_cost = mapping_cost({}, target, base) for other_o in inames: if other_o == o: row.append(unmapped_cost) else: row.append(float('inf')) cost_matrix.append(row) m = Munkres() indices = m.compute(cost_matrix) # comments for using scipy hungarian # indices = linear_sum_assignment(cost_matrix) mapping = {} # for i in range(len(indices[0])): # row = indices[0][i] # col = indices[1][i] for row, col in indices: if col >= len(cnames): mapping[inames[row]] = inames[row] else: mapping[inames[row]] = cnames[col] return frozenset(mapping.items())
def execute_munkres(matrix): m = Munkres() points = m.compute(matrix) result = 0 for point in points: result += matrix[point[0]][point[1]] return result
def _round(self, matrix): m = Munkres() lists = self.matrix_to_lists(matrix) indexes = m.compute(lists) matrix *= 0 for row, column in indexes: matrix[row, column] = 1 return matrix
def match_labels(contingency_table): """Attempt to match the labels between ground truth and prediction using Hungarian algorithm. Extra prediction labels are moved to the right most columns. """ m = Munkres() ind = m.compute(cost_matrix(contingency_table.as_matrix())) return rearrange_columns(ind, contingency_table.copy())
def allocate(self): from debate.models import AdjudicatorAllocation # remove trainees self.adjudicators = filter(lambda a: a.score > self.MIN_SCORE, self.adjudicators) # sort adjudicators and debates in descending score/importance self.adjudicators_sorted = list(self.adjudicators) self.adjudicators_sorted.sort(key=lambda a: a.score, reverse=True) self.debates_sorted = list(self.debates) self.debates_sorted.sort(key=lambda a: a.importance, reverse=True) n_adjudicators = len(self.adjudicators) n_debates = len(self.debates) n_solos = n_debates - (n_adjudicators - n_debates)/2 # get adjudicators that can adjudicate solo chairs = self.adjudicators_sorted[:n_solos] #chairs = [a for a in self.adjudicators_sorted if a.score > # self.CHAIR_CUTOFF] # get debates that will be judged by solo adjudicators chair_debates = self.debates_sorted[:len(chairs)] panel_debates = self.debates_sorted[len(chairs):] panellists = [a for a in self.adjudicators_sorted if a not in chairs] assert len(panel_debates) * 3 <= len(panellists) print "costing chairs" n = len(chairs) cost_matrix = [[0] * n for i in range(n)] for i, debate in enumerate(chair_debates): for j, adj in enumerate(chairs): cost_matrix[i][j] = self.calc_cost(debate, adj) print "optimizing" m = Munkres() indexes = m.compute(cost_matrix) total_cost = 0 for r, c in indexes: total_cost += cost_matrix[r][c] print 'total cost for solos', total_cost print 'number of solo debates', n result = ((chair_debates[i], chairs[j]) for i, j in indexes if i < len(chair_debates)) alloc = [AdjudicatorAllocation(d, c) for d, c in result] print [(a.debate, a.chair) for a in alloc]
def get_order(params, tile_struct, tilesegmentlists, exposurelist, observatory, config_struct): ''' tile_struct: dictionary. key -> struct info. tilesegmentlists: list of lists. Segments for each tile in tile_struct that are available for observation. exposurelist: list of segments that the telescope is supposed to be working. consecutive segments from the start to the end, with each segment size being the exposure time. Returns a list of tile indices in the order of observation. ''' keys = tile_struct.keys() exposureids_tiles = {} first_exposure = np.inf*np.ones((len(keys),)) last_exposure = -np.inf*np.ones((len(keys),)) tileprobs = np.zeros((len(keys),)) tilenexps = np.zeros((len(keys),)) tileexptime = np.zeros((len(keys),)) tilefilts = {} tileavailable = np.zeros((len(keys),)) tileavailable_tiles = {} keynames = [] nexps = 0 for jj, key in enumerate(keys): tileprobs[jj] = tile_struct[key]["prob"] tilenexps[jj] = tile_struct[key]["nexposures"] tilefilts[key] = copy.deepcopy(tile_struct[key]["filt"]) tileavailable_tiles[jj] = [] keynames.append(key) nexps = nexps + tile_struct[key]["nexposures"] if "dec_constraint" in config_struct: dec_constraint = config_struct["dec_constraint"].split(",") dec_min = float(dec_constraint[0]) dec_max = float(dec_constraint[1]) for ii in range(len(exposurelist)): exposureids_tiles[ii] = {} exposureids = [] probs = [] ras, decs = [], [] for jj, key in enumerate(keys): tilesegmentlist = tilesegmentlists[jj] if tile_struct[key]["prob"] == 0: continue if "dec_constraint" in config_struct: if (tile_struct[key]["dec"] < dec_min) or (tile_struct[key]["dec"] > dec_max): continue if "epochs" in tile_struct[key]: if np.any(np.abs(exposurelist[ii][0]-tile_struct[key]["epochs"][:,2]) < params["mindiff"]/86400.0): continue if tilesegmentlist.intersects_segment(exposurelist[ii]): exposureids.append(key) probs.append(tile_struct[key]["prob"]) ras.append(tile_struct[key]["ra"]) decs.append(tile_struct[key]["dec"]) first_exposure[jj] = np.min([first_exposure[jj],ii]) last_exposure[jj] = np.max([last_exposure[jj],ii]) tileavailable_tiles[jj].append(ii) tileavailable[jj] = tileavailable[jj] + 1 # in every exposure, the tiles available for observation exposureids_tiles[ii]["exposureids"] = exposureids # list of tile ids exposureids_tiles[ii]["probs"] = probs # the corresponding probs exposureids_tiles[ii]["ras"] = ras exposureids_tiles[ii]["decs"] = decs exposureids = [] probs = [] ras, decs = [], [] for ii, key in enumerate(keys): # tile_struct[key]["nexposures"]: the number of exposures assigned to this tile for jj in range(tile_struct[key]["nexposures"]): exposureids.append(key) # list of tile ids for every exposure it is allocated to observe probs.append(tile_struct[key]["prob"]) ras.append(tile_struct[key]["ra"]) decs.append(tile_struct[key]["dec"]) idxs = -1*np.ones((len(exposureids_tiles.keys()),)) filts = ['n'] * len(exposureids_tiles.keys()) if nexps == 0: return idxs, filts if params["scheduleType"] == "airmass_weighted": # # first step is to sort the array in order of descending probability indsort = np.argsort(-np.array(probs)) probs = np.array(probs)[indsort] ras = np.array(ras)[indsort] decs = np.array(decs)[indsort] exposureids = np.array(exposureids)[indsort] tilematrix = np.zeros((len(exposurelist), len(ras))) probmatrix = np.zeros((len(exposurelist), len(ras))) for ii in np.arange(len(exposurelist)): # first, create an array of airmass-weighted probabilities t = Time(exposurelist[ii][0], format='mjd') altaz = get_altaz_tiles(ras, decs, observatory, t) alts = altaz.alt.degree horizon = config_struct["horizon"] horizon_mask = alts <= horizon airmass = 1 / np.cos((90. - alts) * np.pi / 180.) below_horizon_mask = horizon_mask * 10.**100 airmass = airmass + below_horizon_mask airmass_weight = 10 ** (0.4 * 0.1 * (airmass - 1) ) tilematrix[ii, :] = np.array(probs/airmass_weight) probmatrix[ii, :] = np.array(probs * (True^horizon_mask)) if params["scheduleType"] == "greedy": for ii in np.arange(len(exposurelist)): exptimecheck = np.where(exposurelist[ii][0]-tileexptime < params["mindiff"]/86400.0)[0] exptimecheckkeys = [keynames[x] for x in exptimecheck] # find_tile finds the tile that covers the largest probablity # restricted by availability of tile and timeallocation idx2, exposureids, probs = find_tile(exposureids_tiles[ii],exposureids,probs,exptimecheckkeys=exptimecheckkeys) if idx2 in keynames: idx = keynames.index(idx2) tilenexps[idx] = tilenexps[idx] - 1 tileexptime[idx] = exposurelist[ii][0] if len(tilefilts[idx2]) > 0: filt = tilefilts[idx2].pop(0) filts[ii] = filt idxs[ii] = idx2 if not exposureids: break elif params["scheduleType"] == "greedy_slew": current_ra, current_dec = np.nan, np.nan for ii in np.arange(len(exposurelist)): exptimecheck = np.where(exposurelist[ii][0]-tileexptime < params["mindiff"]/86400.0)[0] exptimecheckkeys = [keynames[x] for x in exptimecheck] # find_tile finds the tile that covers the largest probablity # restricted by availability of tile and timeallocation idx2, exposureids, probs = find_tile(exposureids_tiles[ii],exposureids,probs,exptimecheckkeys=exptimecheckkeys,current_ra=current_ra,current_dec=current_dec,slew_rate=config_struct['slew_rate'],readout=config_struct['readout']) if idx2 in keynames: idx = keynames.index(idx2) tilenexps[idx] = tilenexps[idx] - 1 tileexptime[idx] = exposurelist[ii][0] if len(tilefilts[idx2]) > 0: filt = tilefilts[idx2].pop(0) filts[ii] = filt current_ra = tile_struct[idx2]["ra"] current_dec = tile_struct[idx2]["dec"] idxs[ii] = idx2 if not exposureids: break elif params["scheduleType"] == "sear": #for ii in np.arange(len(exposurelist)): iis = np.arange(len(exposurelist)).tolist() while len(iis) > 0: ii = iis[0] mask = np.where((ii == last_exposure) & (tilenexps > 0))[0] exptimecheck = np.where(exposurelist[ii][0]-tileexptime < params["mindiff"]/86400.0)[0] exptimecheckkeys = [keynames[x] for x in exptimecheck] if len(mask) > 0: idxsort = mask[np.argsort(tileprobs[mask])] idx2, exposureids, probs = find_tile(exposureids_tiles[ii],exposureids,probs,idxs=idxsort,exptimecheckkeys=exptimecheckkeys) last_exposure[mask] = last_exposure[mask] + 1 else: idx2, exposureids, probs = find_tile(exposureids_tiles[ii],exposureids,probs,exptimecheckkeys=exptimecheckkeys) if idx2 in keynames: idx = keynames.index(idx2) tilenexps[idx] = tilenexps[idx] - 1 tileexptime[idx] = exposurelist[ii][0] if len(tilefilts[idx2]) > 0: filt = tilefilts[idx2].pop(0) filts[ii] = filt idxs[ii] = idx2 iis.pop(0) if not exposureids: break elif params["scheduleType"] == "weighted": for ii in np.arange(len(exposurelist)): jj = exposureids_tiles[ii]["exposureids"] weights = tileprobs[jj] * tilenexps[jj] / tileavailable[jj] weights[~np.isfinite(weights)] = 0.0 exptimecheck = np.where(exposurelist[ii][0]-tileexptime < params["mindiff"]/86400.0)[0] weights[exptimecheck] = 0.0 if np.any(weights >= 0): idxmax = np.argmax(weights) idx2 = jj[idxmax] if idx2 in keynames: idx = keynames.index(idx2) tilenexps[idx] = tilenexps[idx] - 1 tileexptime[idx] = exposurelist[ii][0] if len(tilefilts[idx2]) > 0: filt = tilefilts[idx2].pop(0) filts[ii] = filt idxs[ii] = idx2 tileavailable[jj] = tileavailable[jj] - 1 elif params["scheduleType"] == "airmass_weighted": # then use the Hungarian algorithm (munkres) to schedule high prob tiles at low airmass tilematrix_mask = tilematrix > 10**(-10) if tilematrix_mask.any(): print("Calculating Hungarian solution...") total_cost = 0 cost_matrix = make_cost_matrix(tilematrix) m = Munkres() optimal_points = m.compute(cost_matrix) print("Hungarian solution calculated...") max_no_observ = min(tilematrix.shape) for jj in range(max_no_observ): idx0, idx1 = optimal_points[jj] # idx0 indexes over the time windows, idx1 indexes over the probabilities # idx2 gets the exposure id of the tile, used to assign tileexptime and tilenexps try: idx2 = exposureids[idx1] pamw = tilematrix[idx0][idx1] total_cost += pamw if len(tilefilts[idx2]) > 0: filt = tilefilts[idx2].pop(0) filts[idx0] = filt except: continue idxs[idx0] = idx2 else: print("The localization is not visible from the site.") else: raise ValueError("Scheduling options are greedy/sear/weighted/airmass_weighted, or with _slew.") return idxs, filts
def compute3rdPartyMetrics(self): """ Computes the metrics defined in - Stiefelhagen 2008: Evaluating Multiple Object Tracking Performance: The CLEAR MOT Metrics MOTA, MOTAL, MOTP - Nevatia 2008: Global Data Association for Multi-Object Tracking Using Network Flows MT/PT/ML """ # construct Munkres object for Hungarian Method association hm = Munkres() max_cost = 1e9 # go through all frames and associate ground truth and tracker results # groundtruth and tracker contain lists for every single frame containing lists of KITTI format detections fr, ids = 0, 0 for seq_idx in range(len(self.groundtruth)): seq_gt = self.groundtruth[seq_idx] seq_dc = self.dcareas[seq_idx] # don't care areas seq_tracker = self.tracker[seq_idx] seq_trajectories = defaultdict(list) seq_ignored = defaultdict(list) # statistics over the current sequence, check the corresponding # variable comments in __init__ to get their meaning seqtp = 0 seqitp = 0 seqfn = 0 seqifn = 0 seqfp = 0 seqigt = 0 seqitr = 0 last_ids = [[], []] n_gts = 0 n_trs = 0 for f in range(len(seq_gt)): g = seq_gt[f] dc = seq_dc[f] t = seq_tracker[f] # counting total number of ground truth and tracker objects self.n_gt += len(g) self.n_tr += len(t) n_gts += len(g) n_trs += len(t) # use hungarian method to associate, using boxoverlap 0..1 as cost # build cost matrix cost_matrix = [] this_ids = [[], []] for gg in g: # save current ids this_ids[0].append(gg.track_id) this_ids[1].append(-1) gg.tracker = -1 gg.id_switch = 0 gg.fragmentation = 0 cost_row = [] for tt in t: # overlap == 1 is cost ==0 c = 1 - self.boxoverlap(gg, tt) # gating for boxoverlap if c <= self.min_overlap: cost_row.append(c) else: cost_row.append(max_cost) # = 1e9 cost_matrix.append(cost_row) # all ground truth trajectories are initially not associated # extend groundtruth trajectories lists (merge lists) seq_trajectories[gg.track_id].append(-1) seq_ignored[gg.track_id].append(False) if len(g) is 0: cost_matrix = [[]] # associate association_matrix = hm.compute(cost_matrix) # tmp variables for sanity checks and MODP computation tmptp = 0 tmpfp = 0 tmpfn = 0 tmpc = 0 # this will sum up the overlaps for all true positives tmpcs = [0] * len( g) # this will save the overlaps for all true positives # the reason is that some true positives might be ignored # later such that the corrsponding overlaps can # be subtracted from tmpc for MODP computation # mapping for tracker ids and ground truth ids for row, col in association_matrix: # apply gating on boxoverlap c = cost_matrix[row][col] if c < max_cost: g[row].tracker = t[col].track_id this_ids[1][row] = t[col].track_id t[col].valid = True g[row].distance = c self.total_cost += 1 - c tmpc += 1 - c tmpcs[row] = 1 - c seq_trajectories[g[row].track_id][-1] = t[col].track_id # true positives are only valid associations self.tp += 1 tmptp += 1 else: g[row].tracker = -1 self.fn += 1 tmpfn += 1 # associate tracker and DontCare areas # ignore tracker in neighboring classes nignoredtracker = 0 # number of ignored tracker detections ignoredtrackers = dict() # will associate the track_id with -1 # if it is not ignored and 1 if it is # ignored; # this is used to avoid double counting ignored # cases, see the next loop for tt in t: ignoredtrackers[tt.track_id] = -1 # ignore detection if it belongs to a neighboring class or is # smaller or equal to the minimum height tt_height = abs(tt.y1 - tt.y2) if ((self.cls == "car" and tt.obj_type == "van") or (self.cls == "pedestrian" and tt.obj_type == "person_sitting") or tt_height <= self.min_height) and not tt.valid: nignoredtracker += 1 tt.ignored = True ignoredtrackers[tt.track_id] = 1 continue for d in dc: overlap = self.boxoverlap(tt, d, "a") if overlap > 0.5 and not tt.valid: tt.ignored = True nignoredtracker += 1 ignoredtrackers[tt.track_id] = 1 break # check for ignored FN/TP (truncation or neighboring object class) ignoredfn = 0 # the number of ignored false negatives nignoredtp = 0 # the number of ignored true positives nignoredpairs = 0 # the number of ignored pairs, i.e. a true positive # which is ignored but where the associated tracker # detection has already been ignored gi = 0 for gg in g: if gg.tracker < 0: if gg.occlusion>self.max_occlusion or gg.truncation>self.max_truncation\ or (self.cls=="car" and gg.obj_type=="van") or (self.cls=="pedestrian" and gg.obj_type=="person_sitting"): seq_ignored[gg.track_id][-1] = True gg.ignored = True ignoredfn += 1 elif gg.tracker >= 0: if gg.occlusion>self.max_occlusion or gg.truncation>self.max_truncation\ or (self.cls=="car" and gg.obj_type=="van") or (self.cls=="pedestrian" and gg.obj_type=="person_sitting"): seq_ignored[gg.track_id][-1] = True gg.ignored = True nignoredtp += 1 # if the associated tracker detection is already ignored, # we want to avoid double counting ignored detections if ignoredtrackers[gg.tracker] > 0: nignoredpairs += 1 # for computing MODP, the overlaps from ignored detections # are subtracted tmpc -= tmpcs[gi] gi += 1 # the below might be confusion, check the comments in __init__ # to see what the individual statistics represent # correct TP by number of ignored TP due to truncation # ignored TP are shown as tracked in visualization tmptp -= nignoredtp # count the number of ignored true positives self.itp += nignoredtp # adjust the number of ground truth objects considered self.n_gt -= (ignoredfn + nignoredtp) # count the number of ignored ground truth objects self.n_igt += ignoredfn + nignoredtp # count the number of ignored tracker objects self.n_itr += nignoredtracker # count the number of ignored pairs, i.e. associated tracker and # ground truth objects that are both ignored self.n_igttr += nignoredpairs # false negatives = associated gt bboxes exceding association threshold + non-associated gt bboxes # tmpfn += len(g) - len(association_matrix) - ignoredfn self.fn += len(g) - len(association_matrix) - ignoredfn self.ifn += ignoredfn # false positives = tracker bboxes - associated tracker bboxes # mismatches (mme_t) tmpfp += len( t) - tmptp - nignoredtracker - nignoredtp + nignoredpairs self.fp += len( t) - tmptp - nignoredtracker - nignoredtp + nignoredpairs #tmpfp = len(t) - tmptp - nignoredtp # == len(t) - (tp - ignoredtp) - ignoredtp #self.fp += len(t) - tmptp - nignoredtp # update sequence data seqtp += tmptp seqitp += nignoredtp seqfp += tmpfp seqfn += tmpfn seqifn += ignoredfn seqigt += ignoredfn + nignoredtp seqitr += nignoredtracker # sanity checks # - the number of true positives minues ignored true positives # should be greater or equal to 0 # - the number of false negatives should be greater or equal to 0 # - the number of false positives needs to be greater or equal to 0 # otherwise ignored detections might be counted double # - the number of counted true positives (plus ignored ones) # and the number of counted false negatives (plus ignored ones) # should match the total number of ground truth objects # - the number of counted true positives (plus ignored ones) # and the number of counted false positives # plus the number of ignored tracker detections should # match the total number of tracker detections; note that # nignoredpairs is subtracted here to avoid double counting # of ignored detection sin nignoredtp and nignoredtracker if tmptp < 0: print(tmptp, nignoredtp) raise NameError("Something went wrong! TP is negative") if tmpfn < 0: print(tmpfn, len(g), len(association_matrix), ignoredfn, nignoredpairs) raise NameError("Something went wrong! FN is negative") if tmpfp < 0: print(tmpfp, len(t), tmptp, nignoredtracker, nignoredtp, nignoredpairs) raise NameError("Something went wrong! FP is negative") if tmptp + tmpfn is not len(g) - ignoredfn - nignoredtp: print("seqidx", seq_idx) print("frame ", f) print("TP ", tmptp) print("FN ", tmpfn) print("FP ", tmpfp) print("nGT ", len(g)) print("nAss ", len(association_matrix)) print("ign GT", ignoredfn) print("ign TP", nignoredtp) raise NameError( "Something went wrong! nGroundtruth is not TP+FN") if tmptp + tmpfp + nignoredtp + nignoredtracker - nignoredpairs is not len( t): print(seq_idx, f, len(t), tmptp, tmpfp) print(len(association_matrix), association_matrix) raise NameError( "Something went wrong! nTracker is not TP+FP") # check for id switches or fragmentations for i, tt in enumerate(this_ids[0]): if tt in last_ids[0]: idx = last_ids[0].index(tt) tid = this_ids[1][i] lid = last_ids[1][idx] if tid != lid and lid != -1 and tid != -1: if g[i].truncation < self.max_truncation: g[i].id_switch = 1 ids += 1 if tid != lid and lid != -1: if g[i].truncation < self.max_truncation: g[i].fragmentation = 1 fr += 1 # save current index last_ids = this_ids # compute MOTP_t MODP_t = 1 if tmptp != 0: MODP_t = tmpc / float(tmptp) self.MODP_t.append(MODP_t) # remove empty lists for current gt trajectories self.gt_trajectories[seq_idx] = seq_trajectories self.ign_trajectories[seq_idx] = seq_ignored # gather statistics for "per sequence" statistics. self.n_gts.append(n_gts) self.n_trs.append(n_trs) self.tps.append(seqtp) self.itps.append(seqitp) self.fps.append(seqfp) self.fns.append(seqfn) self.ifns.append(seqifn) self.n_igts.append(seqigt) self.n_itrs.append(seqitr) # compute MT/PT/ML, fragments, idswitches for all groundtruth trajectories n_ignored_tr_total = 0 for seq_idx, (seq_trajectories, seq_ignored) in enumerate( zip(self.gt_trajectories, self.ign_trajectories)): if len(seq_trajectories) == 0: continue tmpMT, tmpML, tmpPT, tmpId_switches, tmpFragments = [0] * 5 n_ignored_tr = 0 for g, ign_g in zip(seq_trajectories.values(), seq_ignored.values()): # all frames of this gt trajectory are ignored if all(ign_g): n_ignored_tr += 1 n_ignored_tr_total += 1 continue # all frames of this gt trajectory are not assigned to any detections if all([this == -1 for this in g]): tmpML += 1 self.ML += 1 continue # compute tracked frames in trajectory last_id = g[0] # first detection (necessary to be in gt_trajectories) is always tracked tracked = 1 if g[0] >= 0 else 0 lgt = 0 if ign_g[0] else 1 for f in range(1, len(g)): if ign_g[f]: last_id = -1 continue lgt += 1 if last_id != g[f] and last_id != -1 and g[f] != -1 and g[ f - 1] != -1: tmpId_switches += 1 self.id_switches += 1 if f < len(g) - 1 and g[f - 1] != g[ f] and last_id != -1 and g[f] != -1 and g[f + 1] != -1: tmpFragments += 1 self.fragments += 1 if g[f] != -1: tracked += 1 last_id = g[f] # handle last frame; tracked state is handled in for loop (g[f]!=-1) if len(g) > 1 and g[f - 1] != g[f] and last_id != -1 and g[ f] != -1 and not ign_g[f]: tmpFragments += 1 self.fragments += 1 # compute MT/PT/ML tracking_ratio = tracked / float(len(g) - sum(ign_g)) if tracking_ratio > 0.8: tmpMT += 1 self.MT += 1 elif tracking_ratio < 0.2: tmpML += 1 self.ML += 1 else: # 0.2 <= tracking_ratio <= 0.8 tmpPT += 1 self.PT += 1 if (self.n_gt_trajectories - n_ignored_tr_total) == 0: self.MT = 0. self.PT = 0. self.ML = 0. else: self.MT /= float(self.n_gt_trajectories - n_ignored_tr_total) self.PT /= float(self.n_gt_trajectories - n_ignored_tr_total) self.ML /= float(self.n_gt_trajectories - n_ignored_tr_total) # precision/recall etc. if (self.fp + self.tp) == 0 or (self.tp + self.fn) == 0: self.recall = 0. self.precision = 0. else: self.recall = self.tp / float(self.tp + self.fn) self.precision = self.tp / float(self.fp + self.tp) if (self.recall + self.precision) == 0: self.F1 = 0. else: self.F1 = 2. * (self.precision * self.recall) / (self.precision + self.recall) if sum(self.n_frames) == 0: self.FAR = "n/a" else: self.FAR = self.fp / float(sum(self.n_frames)) # compute CLEARMOT if self.n_gt == 0: self.MOTA = -float("inf") self.MODA = -float("inf") else: self.MOTA = 1 - (self.fn + self.fp + self.id_switches) / float( self.n_gt) self.MODA = 1 - (self.fn + self.fp) / float(self.n_gt) if self.tp == 0: self.MOTP = float("inf") else: self.MOTP = self.total_cost / float(self.tp) if self.n_gt != 0: if self.id_switches == 0: self.MOTAL = 1 - (self.fn + self.fp + self.id_switches) / float(self.n_gt) else: self.MOTAL = 1 - (self.fn + self.fp + math.log10( self.id_switches)) / float(self.n_gt) else: self.MOTAL = -float("inf") if sum(self.n_frames) == 0: self.MODP = "n/a" else: self.MODP = sum(self.MODP_t) / float(sum(self.n_frames)) return True
class GN(): def __init__(self, seq_index, tt, cuda=True): ''' Evaluating with the MotMetrics :param seq_index: the number of the sequence :param tt: train_test :param length: the number of frames which is used for training :param cuda: True - GPU, False - CPU ''' self.bbx_counter = 0 self.seq_index = seq_index self.hungarian = Munkres() self.device = torch.device("cuda" if cuda else "cpu") self.tt = tt self.missingCounter = 0 self.sideConnection = 0 print ' Loading the model...' self.loadModel() self.out_dir = t_dir + 'motmetrics_%s/'%type if not os.path.exists(self.out_dir): os.mkdir(self.out_dir) else: deleteDir(self.out_dir) os.mkdir(self.out_dir) self.initOut() def initOut(self): print ' Loading Data...' self.train_set = DatasetFromFolder(sequence_dir, '../MOT/MOT16/test/MOT16-%02d'%self.seq_index) detection_dir = self.out_dir +'res_training_det.txt' res_training = self.out_dir + 'res_training.txt' # the result of the training data self.createTxt(detection_dir) self.createTxt(res_training) self.copyLines(self.seq_index, 1, detection_dir, self.tt, 1) self.evaluation(1, self.tt, detection_dir, res_training) def getSeqL(self, info): # get the length of the sequence f = open(info, 'r') f.readline() for line in f.readlines(): line = line.strip().split('=') if line[0] == 'seqLength': seqL = int(line[1]) f.close() return seqL def copyLines(self, seq, head, gt_seq, tail=-1, tag=0): ''' Copy the groun truth within [head, head+num] :param seq: the number of the sequence :param head: the head frame number :param tail: the number the clipped sequence :param gt_seq: the dir of the output file :return: None ''' if tt_tag: basic_dir = '../MOT/MOT%d/test/MOT%d-%02d-%s/' % (year, year, seq, type) else: basic_dir = '../MOT/MOT%d/train/MOT%d-%02d-%s/' % (year, year, seq, type) print ' Testing on', basic_dir, 'Length:', self.tt seqL = tail if tail != -1 else self.getSeqL(basic_dir + 'seqinfo.ini') det_dir = 'gt/gt_det.txt' if test_gt_det else 'det/det.txt' seq_dir = basic_dir + ('gt/gt.txt' if tag == 0 else det_dir) inStream = open(seq_dir, 'r') outStream = open(gt_seq, 'w') for line in inStream.readlines(): line = line.strip() attrs = line.split(',') f_num = int(attrs[0]) if f_num >= head and f_num <= seqL: print >> outStream, line outStream.close() inStream.close() return seqL def createTxt(self, out_file): f = open(out_file, 'w') f.close() def loadModel(self): name = 'all_6' self.Uphi = torch.load('Results/MOT16/IoU/%s/uphi_13.pth'%name).to(self.device) self.Ephi = torch.load('Results/MOT16/IoU/%s/ephi_13.pth'%name).to(self.device) self.u = torch.load('Results/MOT16/IoU/%s/u_13.pth'%name) self.u = self.u.to(self.device) def swapFC(self): self.cur = self.cur ^ self.nxt self.nxt = self.cur ^ self.nxt self.cur = self.cur ^ self.nxt def linearModel(self, out, attr1, attr2): # print 'I got you! *.*' t = attr1[-1] self.sideConnection += 1 if t > f_gap: return frame = int(attr1[0]) x1, y1, w1, h1 = float(attr1[2]), float(attr1[3]), float(attr1[4]), float(attr1[5]) x2, y2, w2, h2 = float(attr2[2]), float(attr2[3]), float(attr2[4]), float(attr2[5]) x_delta = (x2-x1)/t y_delta = (y2-y1)/t w_delta = (w2-w1)/t h_delta = (h2-h1)/2 for i in xrange(1, t): frame += 1 x1 += x_delta y1 += y_delta w1 += w_delta h1 += h_delta attr1[0] = str(frame) attr1[2] = str(x1) attr1[3] = str(y1) attr1[4] = str(w1) attr1[5] = str(h1) line = '' for attr in attr1[:-1]: line += attr + ',' if show_recovering: line += '1' else: line = line[:-1] print >> out, line self.bbx_counter += 1 self.missingCounter += t-1 def evaluation(self, head, tail, gtFile, outFile): ''' Evaluation on dets :param head: the head frame number :param tail: the tail frame number :param gtFile: the ground truth file name :param outFile: the name of output file :return: None ''' gtIn = open(gtFile, 'r') self.cur, self.nxt = 0, 1 line_con = [[], []] id_con = [[], []] id_step = 1 step = head + self.train_set.setBuffer(head) while step < tail: # print '*********************************' t_gap = self.train_set.loadNext() step += t_gap # print head+step, 'F', u_ = self.Uphi(self.train_set.E, self.train_set.V, self.u) # print 'Fo' m = self.train_set.m n = self.train_set.n # print 'm = %d, n = %d'%(m, n) if n==0: print 'There is no detection in the rest of sequence!' break if id_step == 1: out = open(outFile, 'a') i = 0 while i < m: attrs = gtIn.readline().strip().split(',') if float(attrs[6]) >= tau_conf_score: attrs.append(1) attrs[1] = str(id_step) line = '' for attr in attrs[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 line_con[self.cur].append(attrs) id_con[self.cur].append(id_step) id_step += 1 i += 1 out.close() i = 0 while i < n: attrs = gtIn.readline().strip().split(',') if float(attrs[6]) >= tau_conf_score: attrs.append(1) line_con[self.nxt].append(attrs) id_con[self.nxt].append(-1) i += 1 # update the edges # print 'T', ret = self.train_set.getRet() for edge in self.train_set.candidates: e, vs_index, vr_index = edge if ret[vs_index][vr_index] == 1.0: continue e = e.to(self.device).view(1,-1) v1 = self.train_set.getMotion(1, vs_index).to(self.device) v2 = self.train_set.getMotion(0, vr_index, vs_index, line_con[self.cur][vs_index][-1]).to(self.device) e_ = self.Ephi(e, v1, v2, u_) self.train_set.edges[vs_index][vr_index] = e_.data.view(-1) tmp = F.softmax(e_) tmp = tmp.cpu().data.numpy()[0] ret[vs_index][vr_index] = float(tmp[0]) # self.train_set.showE(outFile) # for j in ret: # print j results = self.hungarian.compute(ret) out = open(outFile, 'a') look_up = set(j for j in xrange(n)) for (i, j) in results: # print (i,j) if ret[i][j] >= tau_threshold: continue look_up.remove(j) self.train_set.updateVelocity(i, j, line_con[self.cur][i][-1], False) id = id_con[self.cur][i] id_con[self.nxt][j] = id attr1 = line_con[self.cur][i] attr2 = line_con[self.nxt][j] # print attrs attr2[1] = str(id) if attr1[-1] > 1: # for the missing detections self.linearModel(out, attr1, attr2) line = '' for attr in attr2[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 for j in look_up: self.train_set.updateVelocity(-1, j, tag=False) for i in xrange(n): if id_con[self.nxt][i] == -1: id_con[self.nxt][i] = id_step attrs = line_con[self.nxt][i] attrs[1] = str(id_step) line = '' for attr in attrs[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 id_step += 1 out.close() # For missing & Occlusion index = 0 for (i, j) in results: while i != index: attrs = line_con[self.cur][index] # print '*', attrs, '*' if attrs[-1] + t_gap <= gap: attrs[-1] += t_gap line_con[self.nxt].append(attrs) id_con[self.nxt].append(id_con[self.cur][index]) self.train_set.moveMotion(index) index += 1 index += 1 while index < m: attrs = line_con[self.cur][index] # print '*', attrs, '*' if attrs[-1] + t_gap <= gap: attrs[-1] += t_gap line_con[self.nxt].append(attrs) id_con[self.nxt].append(id_con[self.cur][index]) self.train_set.moveMotion(index) index += 1 # con = self.train_set.cleanEdge() # for i in xrange(len(con)-1, -1, -1): # index = con[i] # del line_con[self.nxt][index] # del id_con[self.nxt][index] line_con[self.cur] = [] id_con[self.cur] = [] # print head+step, results self.train_set.swapFC() self.swapFC() gtIn.close() print ' The results:', id_step, self.bbx_counter
class GN(): def __init__(self, lr=5e-4, batchs=8, cuda=True): ''' :param tt: train_test :param tag: 1 - evaluation on testing data, 0 - without evaluation on testing data :param lr: :param batchs: :param cuda: ''' # all the tensor should set the 'volatile' as True, and False when update the network self.hungarian = Munkres() self.device = torch.device("cuda" if cuda else "cpu") self.nEpochs = 999 self.lr = lr self.batchsize = batchs self.numWorker = 4 self.show_process = 0 # interaction self.step_input = 1 print ' Preparing the model...' self.resetU() self.Uphi = uphi().to(self.device) self.Ephi = ephi().to(self.device) self.criterion = nn.MSELoss() if criterion_s else nn.CrossEntropyLoss() self.criterion = self.criterion.to(self.device) self.optimizer = optim.Adam([{ 'params': self.Uphi.parameters() }, { 'params': self.Ephi.parameters() }], lr=lr) # seqs = [2, 4, 5, 9, 10, 11, 13] # lengths = [600, 1050, 837, 525, 654, 900, 750] seqs = [2, 4, 5, 10] lengths = [600, 1050, 837, 654] for i in xrange(len(seqs)): self.writer = SummaryWriter() # print ' Loading Data...' seq = seqs[i] self.seq_index = seq start = time.time() sequence_dir = '../MOT/MOT16/train/MOT16-%02d' % seq self.outName = t_dir + 'result_%02d.txt' % seq self.train_set = DatasetFromFolder(sequence_dir, self.outName) self.train_test = lengths[i] self.tag = 0 self.loss_threhold = 0.03 self.update() print ' Logging...' t_data = time.time() - start self.log(t_data) def showNetwork(self): # add the graph into tensorboard E = torch.rand(1, 2).to(self.device) V = torch.rand(1, 512).to(self.device) u = torch.rand(1, 100).to(self.device) self.writer.add_graph(self.Uphi, (E, V, u)) E = torch.rand(1, 2).to(self.device) V1 = torch.rand(1, 512).to(self.device) V2 = torch.rand(1, 512).to(self.device) u = torch.rand(1, 100).to(self.device) self.writer.add_graph(self.Ephi, (E, V1, V2, u)) def log(self, t_data): out = open(self.outName, 'a') print >> out, self.criterion print >> out, 'lr:{}'.format(self.lr) print >> out, self.optimizer.state_dict() print >> out, self.Uphi print >> out, self.Ephi print >> out, 'Time consuming for loading datasets:', t_data out.close() # self.showNetwork() def resetU(self): if u_initial: self.u = torch.FloatTensor( [random.random() for i in xrange(u_num)]).view(1, -1) else: self.u = torch.FloatTensor([0.0 for i in xrange(u_num)]).view(1, -1) self.u = self.u.to(self.device) def updateNetwork(self): self.train_set.setBuffer(1) step = 1 average_epoch = 0 edge_counter = 0.0 for head in xrange(1, self.train_test): self.train_set.loadNext() # Get the next frame edge_counter += self.train_set.m * self.train_set.n start = time.time() show_name = 'LOSS_{}'.format(step) print ' Step -', step data_loader = DataLoader(dataset=self.train_set, num_workers=self.numWorker, batch_size=self.batchsize, shuffle=True) for epoch in xrange(1, self.nEpochs): num = 0 epoch_loss = 0.0 arpha_loss = 0.0 for iteration in enumerate(data_loader, 1): index, (e, gt, vs_index, vr_index) = iteration # print '*'*36 # print e.size() # print gt.size() e = e.to(self.device) gt = gt.to(self.device) self.optimizer.zero_grad() u_ = self.Uphi(self.train_set.E, self.train_set.V, self.u) v1 = self.train_set.getMotion(1, vs_index).to(self.device) v2 = self.train_set.getMotion(0, vr_index, vs_index).to(self.device) e_ = self.Ephi(e, v1, v2, u_) if self.show_process: print '-' * 66 print vs_index, vr_index print 'e:', e.cpu().data.numpy()[0][0], print 'e_:', e_.cpu().data.numpy()[0][0], if criterion_s: print 'GT:', gt.cpu().data.numpy()[0][0] else: print 'GT:', gt.cpu().data.numpy()[0] # Penalize the u to let its value not too big # arpha = torch.mean(torch.abs(u_)) # arpha_loss += arpha.item() # arpha.backward(retain_graph=True) # The regular loss # print e_.size(), e_ # print gt.size(), gt loss = self.criterion(e_, gt.squeeze(1)) # print loss epoch_loss += loss.item() loss.backward() # update the network: Uphi and Ephi self.optimizer.step() # Show the parameters of the Uphi and Ephi to check the process of optimiser # print self.Uphi.features[0].weight.data # print self.Ephi.features[0].weight.data # raw_input('continue?') num += self.batchsize if self.show_process and self.step_input: a = raw_input( 'Continue(0-step, 1-run, 2-run with showing)?') if a == '1': self.show_process = 0 elif a == '2': self.step_input = 0 epoch_loss /= num print ' Loss of epoch {}: {}.'.format( epoch, epoch_loss) self.writer.add_scalars(show_name, { 'regular': epoch_loss, 'u': arpha_loss / num * self.batchsize }, epoch) if epoch_loss < self.loss_threhold: break print ' Time consuming:{}\n\n'.format(time.time() - start) self.updateUE() self.train_set.showE() self.showU() average_epoch += epoch self.writer.add_scalar('epoch', epoch, step) step += 1 self.train_set.swapFC() out = open(self.outName, 'a') print >> out, 'Average edge:', edge_counter * 1.0 / step, '.', print >> out, 'Average epoch:', average_epoch * 1.0 / step, 'for', print >> out, 'Random' if edge_initial else 'IoU' out.close() def saveModel(self): print 'Saving the Uphi model...' torch.save(self.Uphi, t_dir + 'uphi_%02d.pth' % self.seq_index) print 'Saving the Ephi model...' torch.save(self.Ephi, t_dir + 'ephi_%02d.pth' % self.seq_index) print 'Saving the global variable u...' torch.save(self.u, t_dir + 'u_%02d.pth' % self.seq_index) print 'Done!' def updateUE(self): u_ = self.Uphi(self.train_set.E, self.train_set.V, self.u) self.u = u_.data # update the edges for edge in self.train_set: e, gt, vs_index, vr_index = edge e = e.to(self.device).view(1, -1) v1 = self.train_set.getMotion(1, vs_index).to(self.device) v2 = self.train_set.getMotion(0, vr_index, vs_index).to(self.device) e_ = self.Ephi(e, v1, v2, u_) self.train_set.edges[vs_index][vr_index] = e_.data.view(-1) def update(self): start = time.time() self.evaluation(1) if self.tag: self.evaluation(self.train_test) self.updateNetwork() self.saveModel() self.evaluation(1) if self.tag: self.evaluation(self.train_test) out = open(self.outName, 'a') print >> out, 'The final time consuming:{}\n\n'.format( (time.time() - start) / 60) out.close() self.outputScalars() def outputScalars(self): self.writer.export_scalars_to_json(t_dir + 'scalars_%02d.json' % self.seq_index) self.writer.close() def evaluation(self, head): self.train_set.setBuffer(head) total_gt = 0.0 total_ed = 0.0 for step in xrange(1, self.train_test): self.train_set.loadNext() # print head+step, 'F', u_ = self.Uphi(self.train_set.E, self.train_set.V, self.u) # print 'Fo' m = self.train_set.m n = self.train_set.n ret = [[0.0 for i in xrange(n)] for j in xrange(m)] step_gt = self.train_set.step_gt total_gt += step_gt # update the edges # print 'T', for edge in self.train_set.candidates: e, gt, vs_index, vr_index = edge e = e.to(self.device).view(1, -1) v1 = self.train_set.getMotion(1, vs_index).to(self.device) v2 = self.train_set.getMotion(0, vr_index, vs_index).to(self.device) e_ = self.Ephi(e, v1, v2, u_) self.train_set.edges[vs_index][vr_index] = e_.data.view(-1) tmp = F.softmax(e_) tmp = tmp.cpu().data.numpy()[0] ret[vs_index][vr_index] = float(tmp[0]) self.train_set.showE() self.showU() # for j in ret: # print j results = self.hungarian.compute(ret) # print head+step, results, step_ed = 0.0 for (j, k) in results: step_ed += self.train_set.gts[j][k].item() total_ed += step_ed # print 'Fi' print ' ', head + step, 'Step ACC:{}/{}({}%)'.format( int(step_ed), int(step_gt), step_ed / step_gt * 100) self.train_set.swapFC() tra_tst = 'training sets' if head == 1 else 'testing sets' print 'Final {} ACC:{}/{}({}%)'.format(tra_tst, int(total_ed), int(total_gt), total_ed / total_gt * 100) out = open(self.outName, 'a') print >> out, 'Final {} ACC:{}/{}({}%)'.format( tra_tst, int(total_ed), int(total_gt), total_ed / total_gt * 100) out.close() def showU(self): out = open(self.outName, 'a') print >> out, ' u' print >> out, self.u.view( 10, -1) # reshape the size of z with aspect of 10 * 10 out.close()
def py_max_match(scores): m = Munkres() tmp = m.compute(scores) tmp = np.array(tmp).astype(np.int32) return tmp
def draw(users, year, courses): """ We produce the following matrix [ (user1) [ item1, item1, item1, (in fact item1 * item1.count, item2, item2, ... item2.count ], (user2) (user3) . . ] This means the hungarian algorithm is going to find the "lowest cost", where every user hopefully one of his choices. This algorithm has a very bad worst case complexity O(n^3), and we need to construct an array of the size user.count * number of items * item.count. This works well when the number of users is < 200 and the number of items < 30. """ matrix = [] for user in users: x = [] for course in courses: for _ in range(0, course['max']): want = False for inner in user['selection'][year]: if inner['name'] == course['name']: x.append(4 - inner['importance'] ) # higher importance => "lower cost" want = True if not want: x.append(10) matrix.append(x) start = datetime.datetime.now() m = Munkres() indexes = m.compute(matrix) print 'Computation took: ' + str(datetime.datetime.now() - start) counter = {} good = 0 if len(indexes) < len(users): raise Exception('Could not calculate any sane result!') for row, column in indexes: index = 0 # try to match the course from the colum index for course in courses: index += course['max'] if column <= index: name = course['name'] break if not counter.has_key(name): counter[name] = 1 else: counter[name] += 1 user = users[row] for selection in user['selection'][year]: if selection['name'] == name: good += 1 if not user.has_key('result'): user['result'] = [None, None] user['result'][year] = name print '%d of %d got at least one of their choices' % (good, len(users))
#Nodes and edges in bio-DRN NBD = [] EBD = [] #Corresponding mapped node of reference GRN NRG = [] for i in range(len(L1)): print(i) YM = Y[L1[i], :][:, L2[i]] YM = reverse(YM) YM = YM.tolist() m = Munkres() indexes = m.compute(YM) print(indexes) for each in indexes: NBD.append(L2[i][each[1]]) NRG.append(L1[i][each[0]]) #Introduce edges in Bio-DRN for u in NBD: for v in NBD: if (u, v) in G2.edges() and (NRG[NBD.index(u)], NRG[NBD.index(v)]) in G.edges(): EBD.append((u, v)) print(len(NBD)) print(len(NRG))
from munkres import Munkres, print_matrix matrix = [[ 5, 3, ], [3, 3], [3, 3]] m = Munkres() indexes = m.compute(matrix) print_matrix(matrix, msg='Lowest cost through this matrix:') total = 0 for row, column in indexes: value = matrix[row][column] total += value print('(%d, %d) -> %d' % (row, column, value)) print('total cost: %d' % total)
def calculateSimilarity(sent1, sent2, isTitle): # Case Correction sent1 = sent1.lower() sent2 = sent2.lower() # Tokenization normalizer = Normalizer() _tokens1 = word_tokenize( normalizer.normalize( sent1.replace('\u200f', '').replace('\ufeff', ''))) _tokens2 = word_tokenize( normalizer.normalize( sent2.replace('\u200f', '').replace('\ufeff', ''))) # Remove punctuations _tokens1 = [x for x in _tokens1 if x not in string.punctuation] _tokens2 = [x for x in _tokens2 if x not in string.punctuation] # Trigram Replacement tokens1_tmp = [] i = 0 while i < len(_tokens1) - 2: trigram = _tokens1[i] + '_' + _tokens1[i + 1] + '_' + _tokens1[i + 2] if trigram in model.wv.vocab: tokens1_tmp.append(_tokens1[i] + '_' + _tokens1[i + 1] + '_' + _tokens1[i + 2]) i += 3 else: tokens1_tmp.append(_tokens1[i]) i += 1 try: tokens1_tmp.append(_tokens1[len(_tokens1) - 2]) tokens1_tmp.append(_tokens1[len(_tokens1) - 1]) except: pass tokens2_tmp = [] i = 0 while i < len(_tokens2) - 2: trigram = _tokens2[i] + '_' + _tokens2[i + 1] + '_' + _tokens2[i + 2] if trigram in model.wv.vocab: tokens2_tmp.append(_tokens2[i] + '_' + _tokens2[i + 1] + '_' + _tokens2[i + 2]) i += 3 else: tokens2_tmp.append(_tokens2[i]) i += 1 try: tokens2_tmp.append(_tokens2[len(_tokens2) - 2]) tokens2_tmp.append(_tokens2[len(_tokens2) - 1]) except: pass # Bigrams Replacement tokens1 = [] i = 0 while i < len(tokens1_tmp) - 1: bigram = tokens1_tmp[i] + '_' + tokens1_tmp[i + 1] if bigram in model.wv.vocab: tokens1.append(tokens1_tmp[i] + '_' + tokens1_tmp[i + 1]) i += 2 else: tokens1.append(tokens1_tmp[i]) i += 1 try: tokens1.append(_tokens1[len(tokens1_tmp) - 1]) except: pass tokens2 = [] i = 0 while i < len(tokens2_tmp) - 1: bigram = tokens2_tmp[i] + '_' + tokens2_tmp[i + 1] if bigram in model.wv.vocab: tokens2.append(tokens2_tmp[i] + '_' + tokens2_tmp[i + 1]) i += 2 else: tokens2.append(tokens2_tmp[i]) i += 1 try: tokens2.append(_tokens2[len(tokens2_tmp) - 1]) except: pass # Model has token? tokens1 = [x for x in tokens1 if x in model.wv.vocab] tokens2 = [x for x in tokens2 if x in model.wv.vocab] tmp_matched_ngrams = 0 tmp_matched_1grams = 0 if len(tokens1) > 0 and len(tokens2) > 0: m = Munkres() pairMatrix = [] for t1 in tokens1: tmpList = [] for t2 in tokens2: tmpList.append(100 * cosine_sim(model[t1], model[t2])) pairMatrix.append(tmpList) cost_matrix = make_cost_matrix(pairMatrix, lambda cost: 100 - cost) indexes = m.compute(cost_matrix) # print_matrix(pairMatrix, msg='Lowest cost through this matrix:') total = 0 for row, column in indexes: value = pairMatrix[row][column] total += value if not isTitle: if '_' in tokens1[row]: tmp_matched_ngrams += 1 elif '_' in tokens2[column]: tmp_matched_ngrams += 1 else: tmp_matched_1grams += 1 # print('(%d, %d) -> %d' % (row, column, value)) # print('total cost: %d' % total) # print(total / len(indexes)) # return total / len(indexes) / 100 return [ 2 * total / (len(tokens1) + len(tokens2)) / 100, tmp_matched_ngrams, tmp_matched_1grams ] else: return [0, 0, 0]
class BaseHungarianAllocator(BaseAdjudicatorAllocator): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) t = self.tournament self.min_score = t.pref('adj_min_score') self.max_score = t.pref('adj_max_score') self.min_voting_score = t.pref('adj_min_voting_score') self.conflict_penalty = t.pref('adj_conflict_penalty') self.history_penalty = t.pref('adj_history_penalty') self.no_panellists = t.pref('no_panellist_position') self.no_trainees = t.pref('no_trainee_position') self.duplicate_allocations = t.pref('duplicate_adjs') self.feedback_weight = self.round.feedback_weight self.extra_messages = "" # Surfaced to users for non-error disclosures self.munkres = Munkres() def allocate(self): self.populate_adj_scores(self.adjudicators) return self.run_allocation(), self.extra_messages def populate_adj_scores(self, adjudicators): score_min = self.min_score score_range = self.max_score - score_min for adj in adjudicators: adj._weighted_score = adj.weighted_score( self.feedback_weight) # used in min_voting_score filter try: adj._normalized_score = (adj._weighted_score - score_min ) / score_range * 5 # to 0-5 range except ZeroDivisionError: adj._normalized_score = 0.0 ntoolarge = [adj._normalized_score > 5.0 for adj in adjudicators].count(True) if ntoolarge > 0: warning_msg = ngettext( "%(count)s normalised score is larger than 5.0.", "%(count)s normalised scores are larger than 5.0.", ntoolarge) % { 'count': ntoolarge } self.extra_messages += " " + warning_msg logger.warning(warning_msg) ntoosmall = [adj._normalized_score < 0.0 for adj in adjudicators].count(True) if ntoosmall > 0: warning_msg = ngettext( "%(count)s normalised score is smaller than 0.0.", "%(count)s normalised scores are smaller than 0.0.", ntoosmall) % { 'count': ntoosmall } self.extra_messages += " " + warning_msg logger.warning(warning_msg) def calc_cost(self, debate, adj, adjustment=0, chair=None): cost = 0 # Normalise debate importances back to the 1-5 (not ±2) range expected normalised_importance = debate.importance + 3 for team in debate.teams: cost += self.conflict_penalty * self.conflicts.conflict_adj_team( adj, team) cost += self.history_penalty * self.history.seen_adj_team( adj, team) if chair: cost += self.conflict_penalty * self.conflicts.conflict_adj_adj( adj, chair) cost += self.history_penalty * self.history.seen_adj_adj( adj, chair) impt = normalised_importance + adjustment diff = 5 + impt - adj._normalized_score if diff > 0.25: cost += 1000 * exp(diff - 0.25) cost += self.max_score - adj._normalized_score return cost def allocate_trainees(self, trainees, allocation, debates): if len(trainees) > 0 and len(debates) > 0: allocation_by_debate = {aa.container: aa for aa in allocation} logger.info("costing trainees") cost_matrix = [] for debate in debates: chair = allocation_by_debate[debate].chair row = [ self.calc_cost(debate, adj, adjustment=-2.0, chair=chair) for adj in trainees ] cost_matrix.append(row) logger.info( "optimizing trainees (matrix size: %d positions by %d trainees)", len(cost_matrix), len(cost_matrix[0])) indices = self.munkres.compute(cost_matrix) total_cost = sum(cost_matrix[i][j] for i, j in indices) logger.info('total cost for %d trainees: %f', len(indices), total_cost) result = ((debates[i], trainees[j]) for i, j in indices if i < len(debates)) for debate, trainee in result: allocation_by_debate[debate].trainees.append(trainee) logger.info("allocating to %s: %s (t)", debate, trainee) def check_matrix_exists(self, n_debates, n_voting): if n_voting == 0: info = _( "There are no adjudicators eligible to be a chair or " "panellist. Try changing the \"Minimum feedback score " "required to be allocated as chair or panellist\" setting " "to something lower than at least some adjudicators' " "current scores, and try again.") logger.info("No adjudicators able to panel or chair") raise AdjudicatorAllocationError(info) if n_debates == 0: info = _("There are no debates for this round. " "Maybe you haven't created a draw yet?") logger.info("No debates available for allocator") raise AdjudicatorAllocationError(info)
def __init__(self, orig_cost_matrix, required_cells, excluded_cells, orig_cost_matrix_index): ''' Following the terminology used by [1], a node is defined to be a nonempty subset of possible assignments to a cost matrix. Every assignment in node N is required to contain required_cells and exclude excluded_cells. Inputs: - orig_cost_matrix: (2d numpy array) the original cost matrix - required_cells: (list of pairs) where each pair represents a (zero indexed) location in the assignment matrix that must be a 1 - excluded_cells: list of pairs) where each pair represents a (zero indexed) location in the assignment matrix that must be a 0 - orig_cost_matrix_index: index of the cost matrix this Node is descended from, used when when finding the k lowest cost assignments among a group of assignment matrices (k_best_assign_mult_cost_matrices) ''' self.orig_cost_matrix = np.array(orig_cost_matrix, copy=True) self.required_cells = required_cells[:] self.excluded_cells = excluded_cells[:] self.orig_cost_matrix_index = orig_cost_matrix_index if DEBUG: print "New Node:" print "self.required_cells:", self.required_cells print "self.excluded_cells:", self.excluded_cells #we will transform the cost matrix into the "remaining cost matrix" as described in [1] self.remaining_cost_matrix = self.construct_remaining_cost_matrix() assert ((self.remaining_cost_matrix > 0).all()), self.remaining_cost_matrix #solve the assignment problem for the remaining cost matrix hm = Munkres() # we get a list of (row, col) associations, or 1's in the minimum assignment matrix association_list = hm.compute(self.remaining_cost_matrix.tolist()) if DEBUG: print "remaining cost matrix:" print self.remaining_cost_matrix print "association_list" print association_list #compute the minimum cost assignment for the node self.minimum_cost = 0 for (row, col) in association_list: # print 'a', self.minimum_cost, type(self.minimum_cost) # print 'b', self.remaining_cost_matrix[row][col], type(self.remaining_cost_matrix[row][col]) # print 'c', self.minimum_cost +self.remaining_cost_matrix[row][col], type(self.minimum_cost +self.remaining_cost_matrix[row][col]) #np.asscalar important for avoiding overflow problems self.minimum_cost += np.asscalar( self.remaining_cost_matrix[row][col]) for (row, col) in self.required_cells: #np.asscalar important for avoiding overflow problems self.minimum_cost += np.asscalar(orig_cost_matrix[row][col]) #store the minimum cost associations with indices consistent with the original cost matrix self.min_cost_associations = self.get_orig_indices(association_list) if DEBUG: print "New Node:" print "self.required_cells:", self.required_cells print "self.excluded_cells:", self.excluded_cells print print
] # Model has token? posTokens1 = [x for x in posTokens1 if x[0] in model.vocab] posTokens2 = [x for x in posTokens2 if x[0] in model.vocab] m = Munkres() pairMatrix = [] for t1 in tokens1: tmpList = [] for t2 in tokens2: tmpList.append(100 * cosine_sim(model[t1], model[t2])) pairMatrix.append(tmpList) cost_matrix = make_cost_matrix(pairMatrix, lambda cost: 100 - cost) indexes = m.compute(cost_matrix) # print_matrix(pairMatrix, msg='Lowest cost through this matrix:') total = 0 for row, column in indexes: value = pairMatrix[row][column] total += value # print('(%d, %d) -> %d' % (row, column, value)) # print('total cost: %d' % total) # print(total / len(indexes)) g.write(str(int(total / len(indexes) / 20))) g.write('\n') # print(stats.pearsonr([1, 2, 3, 4, 5], [1, 2, 3, 4, 4000]))
class TestHungarian(): """ Imported Munkres module that provides an implementation of the Munkres algorithm that can be used to test my implementation. Generates 10 balanced matrices and 10 unbalanced matrices of maximum size 'max_problem_size that tests are run on How to install munkres test module: try: 'pip install munkres3' If pip install does not work the module named 'munkres3-1.0.5.5' exists in the same folder as this file. When inside folder run: 'python3 setup.py install' """ def __init__(self, max_problem_size): self.h = Hungarian() self.m = Munkres() self.matrices = [] self.rectangular_matrices = [] # Generate random matrices used for testing for i in range(1, 11): rand_int1 = randint(1, max_problem_size) rand_int2 = randint(1, max_problem_size) self.matrices.append( np.random.randint(max_problem_size, size=(rand_int1, rand_int1))) # balanced matrices self.rectangular_matrices.append( np.random.randint(max_problem_size, size=(rand_int1, rand_int2))) # unbalanced matrices def pretty_print_assignments(self, assignments, matrix): """ Pretty prints assignments and it's profit :param assignments: assignments from node in X to node in Y. dict<int, int> :param matrix: NxN profit matrix. Profit from X assigned to Y. :return: Total profit of assignments """ total_profit = 0 for key, value in assignments.items(): profit = matrix[key][value] total_profit += profit print('(%d, %d) -> %d' % (key, value, profit)) print('total profit=%d' % total_profit) return total_profit def max_to_min_problem(self, matrix): """ Convert from maximization to min problem """ cost_matrix = [] for row in matrix: cost_row = [] for col in row: cost_row += [sys.maxsize - col] cost_matrix += [cost_row] return cost_matrix def convert_to_dict(self, indexes): """ This module uses lists to represents assignments whereas my implementation uses dict """ assignments = {} for pair in indexes: assignments[pair[0]] = pair[1] return assignments def compute_test_assignments(self, matrix): """ Compute assignments using imported munkres """ cost_matrix = self.max_to_min_problem(matrix) indexes = self.m.compute(cost_matrix) total = 0 return self.convert_to_dict(indexes) def print_balanced_matrix(self, matrix, msg): (a, b) = matrix.shape if a > b: padding = ((0, 0), (0, a - b)) else: padding = ((0, b - a), (0, 0)) balanced_matrix = np.pad(matrix, padding, mode='constant', constant_values=0) print_matrix(balanced_matrix, msg=msg) def run_test(self): """ Runs anton's implementation of the hungarian algorithm and compares the results to the results of the imported munkres module. The munkres module will balance the problem automatically. Anton's implementation has it's own balancing function. Assignments can differ between the two algorithms, but the total the number of assignments and total profit should always be equal. """ test_matrices = self.matrices + self.rectangular_matrices for index, matrix in enumerate(test_matrices, start=1): print("\n\n----- TEST %d ------ " % (index)) print_matrix(matrix, msg='Original matrix:') self.print_balanced_matrix(matrix, msg='\nBalanced matrix:') print("\nAnton's assignments:") self.h.compute_assignments(matrix) self.h.pretty_print_assignments() print("Correct assignments:") valid_assignments = self.compute_test_assignments( matrix) # will balance matrices using munkres module valid_profit = self.pretty_print_assignments( valid_assignments, matrix) assert self.h.total_profit == valid_profit # make sure total profit is correct assert len(self.h.matching) == len( valid_assignments ) # make sure that dummy row/columns have been removed
class GN(): def __init__(self, seq_index, begin, end, cuda=True): ''' Evaluating with the MotMetrics :param seq_index: the number of the sequence :param tt: train_test :param length: the number of frames which is used for training :param cuda: True - GPU, False - CPU ''' self.bbx_counter = 0 self.seq_index = seq_index self.hungarian = Munkres() self.device = torch.device("cuda" if cuda else "cpu") self.begin = begin self.end = end self.missingCounter = 0 self.sideConnection = 0 print ' Loading the model...' self.loadModel() if train_set_num == 4: self.out_dir = t_dir + 'motmetrics_%s_4%s%.2f%s%s/' % ( type, decay_dir, decay, recover_dir, u_dir) else: # divide each sequence into two parts with proportion 4:1 self.out_dir = t_dir + 'motmetrics_%s_4%s%.2f%s%s_fgap_%d_dseq_longer0/' % ( type, decay_dir, decay, recover_dir, u_dir, f_gap) print self.out_dir if not os.path.exists(self.out_dir): os.mkdir(self.out_dir) else: deleteDir(self.out_dir) os.mkdir(self.out_dir) self.initOut() def initOut(self): print ' Loading Data...' self.train_set = DatasetFromFolder( sequence_dir, '../MOT/MOT16/train/MOT16-%02d' % self.seq_index, tau_conf_score) gt_training = self.out_dir + 'gt_training.txt' # the gt of the training data self.copyLines(self.seq_index, self.begin, gt_training, self.end) detection_dir = self.out_dir + 'res_training_det.txt' res_training = self.out_dir + 'res_training.txt' # the result of the training data self.createTxt(detection_dir) self.createTxt(res_training) self.copyLines(self.seq_index, self.begin, detection_dir, self.end, 1) self.evaluation(self.begin, self.end, detection_dir, res_training) def getSeqL(self, info): # get the length of the sequence f = open(info, 'r') f.readline() for line in f.readlines(): line = line.strip().split('=') if line[0] == 'seqLength': seqL = int(line[1]) f.close() return seqL def copyLines(self, seq, head, gt_seq, tail=-1, tag=0): ''' Copy the groun truth within [head, head+num] :param seq: the number of the sequence :param head: the head frame number :param tail: the number the clipped sequence :param gt_seq: the dir of the output file :return: None ''' if tt_tag: basic_dir = '../MOT/MOT%d/test/MOT%d-%02d-%s/' % (year, year, seq, type) else: basic_dir = '../MOT/MOT%d/train/MOT%d-%02d-%s/' % (year, year, seq, type) print ' Testing on', basic_dir, 'Length:', self.end - self.begin + 1 seqL = tail if tail != -1 else self.getSeqL(basic_dir + 'seqinfo.ini') det_dir = 'gt/gt_det.txt' if test_gt_det else 'det/det.txt' seq_dir = basic_dir + ('gt/gt.txt' if tag == 0 else det_dir) inStream = open(seq_dir, 'r') outStream = open(gt_seq, 'w') for line in inStream.readlines(): line = line.strip() attrs = line.split(',') f_num = int(attrs[0]) if f_num >= head and f_num <= seqL: print >> outStream, line outStream.close() inStream.close() return seqL def createTxt(self, out_file): f = open(out_file, 'w') f.close() def loadModel(self): # name = 'longterm_all_%d'%train_set_num name = 'all_%d' % train_set_num tail = 10 if train_set_num == 4 else 13 if edge_initial == 1: i_name = 'Random' elif edge_initial == 0: i_name = 'IoU' elif edge_initial == 3: i_name = 'Equal' print 'Loading model from', i_name self.Uphi = torch.load('Results/MOT16/%s/%s/uphi_%d.pth' % (i_name, name, tail)).to(self.device) self.Ephi = torch.load('Results/MOT16/%s/%s/ephi_%d.pth' % (i_name, name, tail)).to(self.device) self.u = torch.load('Results/MOT16/%s/%s/u_%d.pth' % (i_name, name, tail)) self.u = self.u.to(self.device) def linearModel(self, out, attr1, attr2): # print 'I got you! *.*' t = attr1[-1] self.sideConnection += 1 if t > f_gap: return frame = int(attr1[0]) x1, y1, w1, h1 = float(attr1[2]), float(attr1[3]), float( attr1[4]), float(attr1[5]) x2, y2, w2, h2 = float(attr2[2]), float(attr2[3]), float( attr2[4]), float(attr2[5]) x_delta = (x2 - x1) / t y_delta = (y2 - y1) / t w_delta = (w2 - w1) / t h_delta = (h2 - h1) / t if t > 1: print 'Linear:', attr1, attr2 for i in xrange(1, t): frame += 1 x1 += x_delta y1 += y_delta w1 += w_delta h1 += h_delta attr1[0] = str(frame) attr1[2] = str(x1) attr1[3] = str(y1) attr1[4] = str(w1) attr1[5] = str(h1) line = '' for attr in attr1[:-1]: line += attr + ',' if show_recovering: line += '1' else: line = line[:-1] # print "liner:", line print >> out, line self.bbx_counter += 1 self.missingCounter += t - 1 def evaluation(self, head, tail, gtFile, outFile): ''' Evaluation on dets :param head: the head frame number :param tail: the tail frame number :param gtFile: the ground truth file name :param outFile: the name of output file :return: None ''' gtIn = open(gtFile, 'r') self.cur, self.nxt = 0, 1 line_con = [[], []] id_con = [] id_step = 1 step = head + self.train_set.setBuffer(head) while step < tail: # print '*********************************' t_gap = self.train_set.loadNext() step += t_gap print head + step, if (head + step) % 30 == 0: print '' # print 'Fo' m = self.train_set.m n = self.train_set.n # print 'm = %d, n = %d'%(m, n) if n == 0: print 'There is no detection in the rest of sequence!' break if id_step == 1: out = open(outFile, 'a') i = 0 while i < m: attrs = gtIn.readline().strip().split(',') if float(attrs[6]) >= tau_conf_score: attrs.append(1) attrs[1] = str(id_step) line = '' for attr in attrs[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 line_con[self.cur].append(attrs) id_con.append(id_step) id_step += 1 i += 1 out.close() i = 0 while i < n: attrs = gtIn.readline().strip().split(',') if float(attrs[6]) >= tau_conf_score: attrs.append(1) line_con[self.nxt].append(attrs) i += 1 # update the edges # print 'T', if u_update: u_ = [] for i in xrange(len(self.train_set.E)): # print 'The aggregation of Edges and Nodes:' # print self.train_set.E[i].size() # print self.train_set.V[i].size() # print self.u.size() u_.append( self.Uphi(self.train_set.E[i], self.train_set.V[i], self.u)) self.u = u_[0].data ret = self.train_set.getRet() decay_tag = [0 for i in xrange(m)] for i in xrange(m): for j in xrange(n): if ret[i][j] == 0: decay_tag[i] += 1 for edge in self.train_set.candidates: edges, indexes, vs_index, vr_index = edge if ret[vs_index][vr_index] == tau_threshold: continue costs = [] v1s = self.train_set.getMotion(1, vs_index) v2s = self.train_set.getMotion(0, vr_index, vs_index) for i in xrange(len(indexes)): index = indexes[i] e = edges[i] if e is not None: e = e.to(self.device).view(1, -1) e_ = self.Ephi(e, v1s[index], v2s[index], u_[i]) tmp = F.softmax(e_) tmp = tmp.cpu().data.numpy()[0] costs.append(tmp[0]) t = line_con[self.cur][vs_index][-1] # ret[vs_index][vr_index] = float(tmp[0])*pow(decay, t-1) cost = sum(costs) / len(costs) if decay_tag[vs_index] > 0: ret[vs_index][vr_index] = min(cost * pow(decay, t - 1), 1.0) else: ret[vs_index][vr_index] = float(cost) # self.train_set.showE(outFile) # for j in ret: # print j results = self.hungarian.compute(ret) out = open(outFile, 'a') look_up = set(j for j in xrange(n)) for (i, j) in results: # print (i,j) if ret[i][j] >= tau_threshold: continue look_up.remove(j) self.train_set.updateVelocity(i, j, False) id = id_con[i] attr1 = line_con[self.cur][i] attr2 = line_con[self.nxt][j] # print attrs attr2[1] = str(id) if attr1[-1] > 1: # for the missing detections self.linearModel(out, attr1, attr2) line = '' for attr in attr2[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] # print 'Association:', line print >> out, line self.bbx_counter += 1 line_con[self.cur][i] = attr2 # print attr1 # print line_con[self.cur][i] # raw_input('continue?') for j in look_up: self.train_set.updateVelocity(-1, j, tag=False) attrs = line_con[self.nxt][j] attrs[1] = str(id_step) line_con[self.cur].append(line_con[self.nxt][j]) id_con.append(id_step) line = '' for attr in attrs[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] # print 'New objects:', line print >> out, line self.bbx_counter += 1 id_step += 1 out.close() # raw_input('Continue?') # Remove the occluded objects index = n - 1 while index >= 0: attrs = line_con[self.cur][index] # print '*', attrs, '*' if attrs[-1] + t_gap <= gap: attrs[-1] += t_gap - 1 else: del line_con[self.cur][index] del id_con[index] self.train_set.deleteMotion(index) index -= 1 line_con[self.nxt] = [] # print head+step, results gtIn.close() print ' The results:', id_step, self.bbx_counter
class TrackingByDetection(object): """(Forward/backward) tracking by detection Parameters ---------- detect_func : func Detection function. Should take video frame as input and return list (or iterable) of detections as (left, top, right, bottom) tuples. detect_smallest : int, optional Smallest object (height, in pixels) that `detect_func` can detect. Defaults to any object. detect_min_size : float, optional Approximate size (in video height ratio) of the smallest object that should be detected. Defaults to any object. detect_every : float, optional When provided, `detect_func` is applied every `detect_every` seconds. Defaults to processing every frame. track_min_confidence : float, optional Kill trackers whose confidence goes below this value. Defaults to 10. track_min_overlap_ratio : float, optional Do not associate trackers and detections if their overlap ratio goes below this value. Defaults to 0.3. track_max_gap : float, optional Bridge gaps with duration shorter than this value. Usage ----- >>> from pyannote.video import Video, TrackingByDetection >>> video = Video(path_to_video) >>> # load segmentation into shots >>> tracking = TrackingByDetection() >>> for face_track in tracking(video, shots): ... # do something with face track ... pass """ def __init__(self, detect_func, detect_smallest=1, detect_min_size=0., detect_every=0., track_min_confidence=10., track_min_overlap_ratio=0.3, track_max_gap=0.): super(TrackingByDetection, self).__init__() self.detect_func = detect_func self.detect_smallest = detect_smallest self.detect_min_size = detect_min_size self.detect_every = detect_every self.track_min_confidence = track_min_confidence self.track_min_overlap_ratio = track_min_overlap_ratio self.track_max_gap = track_max_gap self._hungarian = Munkres() def _kill_tracker(self, identifier): """Kill specific tracker""" del self._trackers[identifier] del self._confidences[identifier] del self._previous[identifier] def _match(self, rectangle1, rectangle2): overlap = rectangle1.intersect(rectangle2).area() if ((overlap < self.track_min_overlap_ratio * rectangle1.area()) or (overlap < self.track_min_overlap_ratio * rectangle2.area())): overlap = 0. return overlap def _associate(self, trackers, detections): """Associate trackers and detections with Hungarian algorithm Parameters ---------- trackers : dict Dictionary where values are current trackers and keys are trackers identifiers. detections : list List of detections Returns ------- match : dict Dictionary where values are trackers and keys are matched detection indices. """ n_trackers, n_detections = len(trackers), len(detections) if n_trackers < 1 or n_detections < 1: return dict() n = max(n_trackers, n_detections) overlap_area = np.zeros((n, n)) # list of (identifier, tracker) tuple trackers_ = trackers.items() for t, (identifier, tracker) in enumerate(trackers_): position = tracker.get_position() for d, detection in enumerate(detections): rectangle = dlib.drectangle(*detection) overlap_area[t, d] = self._match(position, rectangle) # find the best one-to-one mapping match = {} mapping = self._hungarian.compute(np.max(overlap_area) - overlap_area) for t, d in mapping: if t >= n_trackers or d >= n_detections: continue if overlap_area[t, d] > 0.: identifier, _ = trackers_[t] match[d] = identifier return match def _track(self, direction=FORWARD): """Actual tracking based on existing detections""" if direction == FORWARD: frame_cache = self._frame_cache elif direction == BACKWARD: frame_cache = reversed(self._frame_cache) else: raise NotImplementedError() self._trackers = {} self._confidences = {} self._previous = {} new_identifier = 0 for t, frame in frame_cache: # update trackers & end those with low confidence for identifier, tracker in list(self._trackers.items()): confidence = tracker.update(frame) self._confidences[identifier] = confidence if confidence < self.track_min_confidence: self._kill_tracker(identifier) # match trackers with detections at time t detections = [d for _, d, status in self._tracking_graph[t] if status == DETECTION] match = self._associate(self._trackers, detections) # process all matched trackers for d, identifier in match.items(): # connect the previous position of the tracker # to the (current) associated detection current = (t, detections[d], DETECTION) self._tracking_graph.add_edge( self._previous[identifier], current, confidence=self._confidences[identifier]) # end the tracker self._kill_tracker(identifier) # process all unmatched trackers for identifier, tracker in self._trackers.items(): # connect the previous position of the tracker # to the current position of the tracker position = tracker.get_position() position = ( position.left(), position.top(), position.right(), position.bottom() ) current = (t, position, direction) self._tracking_graph.add_edge( self._previous[identifier], current, confidence=self._confidences[identifier]) # save current position of the tracker for next iteration self._previous[identifier] = current # start new trackers for all detections for d, detection in enumerate(detections): # start new tracker new_tracker = dlib.correlation_tracker() new_tracker.start_track(frame, dlib.drectangle(*detection)) self._trackers[new_identifier] = new_tracker # save previous (t, position, status) tuple current = (t, detection, DETECTION) self._previous[new_identifier] = current # increment tracker identifier new_identifier = new_identifier + 1 def _fix(self, track): """Fix track by merging matching forward/backward tracklets""" fixed_track = [] for t, group in itertools.groupby(sorted(track), key=lambda x: x[0]): group = list(group) # make sure all positions are overlap enough error = False for (_, pos1, _), (_, pos2, _) in itertools.combinations(group, 2): rectangle1 = dlib.drectangle(*pos1) rectangle2 = dlib.drectangle(*pos2) if self._match(rectangle1, rectangle2) == 0: error = True break # status status = "+".join( sorted((status for _, _, status in group), key=lambda s: {DETECTION: 2, FORWARD: 1, BACKWARD: 3}[s])) if error: status = "error({0})".format(status) # average position pos = tuple(int(round(v)) for v in np.mean(np.vstack([p for _, p, _ in group]), axis=0)) fixed_track.append((t, pos, status)) return fixed_track def _fill_gaps(self, tracks): # sort tracks by start and end timestamps tracks = sorted(tracks, key=get_min_max_t) # build graph where nodes are tracks and where matching tracks # less than "track_max_gap" away are connected graph = nx.Graph() for i in xrange(len(tracks)): graph.add_node(i) for i, j in itertools.combinations(xrange(len(tracks)), 2): # only try to match tracks with a short gap between them ti = tracks[i][-1][0] tj = tracks[j][0][0] if (tj < ti) or (tj - ti > self.track_max_gap): continue # match tracks whose last and first position match rectangle1 = dlib.drectangle(*tracks[i][-1][1]) rectangle2 = dlib.drectangle(*tracks[j][0][1]) if self._match(rectangle1, rectangle2): graph.add_edge(i, j) # merge tracks that are in the same connected component merged_tracks = [] for group in nx.connected_components(graph): track = [item for t in sorted(group) for item in tracks[t]] merged_tracks.append(track) return merged_tracks def _forward_backward(self): # forward tracking self._track(direction=FORWARD) # backward tracking self._track(direction=BACKWARD) # remove timestamps timestamps = [t for t in self._tracking_graph if not isinstance(t, tuple)] self._tracking_graph.remove_nodes_from(timestamps) # tracks are connected components in tracking graph tracks = nx.connected_components( self._tracking_graph.to_undirected(reciprocal=False)) # merge matching backward/forward tracks tracks = [self._fix(track) for track in tracks] # fill gaps tracks = self._fill_gaps(tracks) # sort tracks by start and end timestamps for track in sorted(tracks, key=get_min_max_t): yield track def _reset(self): """Reset tracking""" self._frame_cache = [] self._tracking_graph = nx.DiGraph() def _normalize_track(self, track, frame_width, frame_height): normalized_track = [] for (t, (left, top, right, bottom), status) in track: left = left / frame_width right = right / frame_width top = top / frame_height bottom = bottom / frame_height normalized_track.append((t, (left, top, right, bottom), status)) return normalized_track def __call__(self, video, segmentation): """ Parameters ---------- video : Video segmentation : """ # should detection be applied to every frame or once every "x" frames? if self.detect_every > 0.0: every_x_frames = int(self.detect_every * video.frame_rate) else: every_x_frames = 1 # estimate downscaling ratio width, height = video.size ratio = 1.0 if self.detect_min_size > 0.0: ratio = self.detect_smallest / (self.detect_min_size * height) ratio = min(1.0, ratio) # tell video instance how to downscale its frames # (and keep track of previous setting) old_frame_width, old_frame_height = video.frame_size frame_width = int(width * ratio) frame_height = int(height * ratio) video.frame_size = (frame_width, frame_height) segment_generator = get_segment_generator(segmentation) segment_generator.send(None) self._reset() for i, (t, frame) in enumerate(video): segment = segment_generator.send(t) if segment: # forward/backward tracking for track in self._forward_backward(): yield self._normalize_track(track, frame_width, frame_height) # start fresh for next segment self._reset() # cache frame (for faster tracking) self._frame_cache.append((t, frame)) self._tracking_graph.add_node(t) # apply detection every x frames if i % every_x_frames == 0: for detection in self.detect_func(frame): self._tracking_graph.add_edge(t, (t, detection, DETECTION)) for track in self._forward_backward(): yield self._normalize_track(track, frame_width, frame_height) # revert frame size to its original setting if self.detect_min_size > 0.0: video.frame_size = (old_frame_width, old_frame_height)
class GN(): def __init__(self, seq_index, tt, cuda=True): ''' Evaluating with the MotMetrics :param seq_index: the number of the sequence :param tt: train_test :param length: the number of frames which is used for training :param cuda: True - GPU, False - CPU ''' self.bbx_counter = 0 self.seq_index = seq_index self.hungarian = Munkres() self.device = torch.device("cuda" if cuda else "cpu") self.tt = tt self.alpha = 0.7 self.missingCounter = 0 self.sideConnection = 0 print ' Loading the model...' self.loadAModel() self.loadMModel() self.out_dir = t_dir + 'motmetrics_%s_7%s%s_tau_crowdeddecay/' % ( type, recover_dir, u_dir) print self.out_dir if not os.path.exists(self.out_dir): os.mkdir(self.out_dir) else: deleteDir(self.out_dir) os.mkdir(self.out_dir) self.initOut() def initOut(self): print ' Loading Data...' self.a_train_set = ADatasetFromFolder( sequence_dir, '../MOT/MOT16/test/MOT16-%02d' % self.seq_index, tau_conf_score) self.m_train_set = MDatasetFromFolder( sequence_dir, '../MOT/MOT16/test/MOT16-%02d' % self.seq_index, tau_conf_score) detection_dir = self.out_dir + 'res_training_det.txt' res_training = self.out_dir + 'res_training.txt' # the result of the training data self.createTxt(detection_dir) self.createTxt(res_training) self.copyLines(self.seq_index, 1, detection_dir, self.tt, 1) self.evaluation(1, self.tt, detection_dir, res_training) def getSeqL(self, info): # get the length of the sequence f = open(info, 'r') f.readline() for line in f.readlines(): line = line.strip().split('=') if line[0] == 'seqLength': seqL = int(line[1]) f.close() return seqL def copyLines(self, seq, head, gt_seq, tail=-1, tag=0): ''' Copy the groun truth within [head, head+num] :param seq: the number of the sequence :param head: the head frame number :param tail: the number the clipped sequence :param gt_seq: the dir of the output file :return: None ''' if tt_tag: basic_dir = '../MOT/MOT%d/test/MOT%d-%02d-%s/' % (year, year, seq, type) else: basic_dir = '../MOT/MOT%d/train/MOT%d-%02d-%s/' % (year, year, seq, type) print ' Testing on', basic_dir, 'Length:', self.tt seqL = tail if tail != -1 else self.getSeqL(basic_dir + 'seqinfo.ini') det_dir = 'gt/gt_det.txt' if test_gt_det else 'det/det.txt' seq_dir = basic_dir + ('gt/gt.txt' if tag == 0 else det_dir) inStream = open(seq_dir, 'r') outStream = open(gt_seq, 'w') for line in inStream.readlines(): line = line.strip() attrs = line.split(',') f_num = int(attrs[0]) if f_num >= head and f_num <= seqL: print >> outStream, line outStream.close() inStream.close() return seqL def createTxt(self, out_file): f = open(out_file, 'w') f.close() def loadAModel(self): from mot_model import uphi, ephi, vphi if edge_initial == 0: model_dir = 'App2_bb' name = '%s_7' % app_dir i_name = 'IoU' elif edge_initial == 1: model_dir = 'App2_bb' name = '%s_7' % app_dir i_name = 'Random' tail = 13 self.AUphi = torch.load('../%s/Results/MOT16/%s/%s/uphi_%02d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.AVphi = torch.load('../%s/Results/MOT16/%s/%s/vphi_%02d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.AEphi1 = torch.load('../%s/Results/MOT16/%s/%s/ephi1_%02d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.AEphi2 = torch.load('../%s/Results/MOT16/%s/%s/ephi2_%02d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.Au = torch.load('../%s/Results/MOT16/%s/%s/u_%02d.pth' % (model_dir, i_name, name, tail)) self.Au = self.Au.to(self.device) def loadMModel(self): from m_mot_model import uphi, ephi if edge_initial == 0: model_dir = 'Motion1_bb' name = 'all_7' i_name = 'IoU' elif edge_initial == 1: model_dir = 'Motion1_bb' name = 'all_7' i_name = 'Random' tail = 13 self.MUphi = torch.load('../%s/Results/MOT16/%s/%s/uphi_%d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.MEphi = torch.load('../%s/Results/MOT16/%s/%s/ephi_%d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.Mu = torch.load('../%s/Results/MOT16/%s/%s/u_%d.pth' % (model_dir, i_name, name, tail)) self.Mu = self.Mu.to(self.device) def swapFC(self): self.cur = self.cur ^ self.nxt self.nxt = self.cur ^ self.nxt self.cur = self.cur ^ self.nxt def linearModel(self, out, attr1, attr2): # print 'I got you! *.*' t = attr1[-1] self.sideConnection += 1 if t > f_gap: return frame = int(attr1[0]) x1, y1, w1, h1 = float(attr1[2]), float(attr1[3]), float( attr1[4]), float(attr1[5]) x2, y2, w2, h2 = float(attr2[2]), float(attr2[3]), float( attr2[4]), float(attr2[5]) x_delta = (x2 - x1) / t y_delta = (y2 - y1) / t w_delta = (w2 - w1) / t h_delta = (h2 - h1) / 2 for i in xrange(1, t): frame += 1 x1 += x_delta y1 += y_delta w1 += w_delta h1 += h_delta attr1[0] = str(frame) attr1[2] = str(x1) attr1[3] = str(y1) attr1[4] = str(w1) attr1[5] = str(h1) line = '' for attr in attr1[:-1]: line += attr + ',' if show_recovering: line += '1' else: line = line[:-1] print >> out, line self.bbx_counter += 1 self.missingCounter += t - 1 def evaluation(self, head, tail, gtFile, outFile): ''' Evaluation on dets :param head: the head frame number :param tail: the tail frame number :param gtFile: the ground truth file name :param outFile: the name of output file :return: None ''' gtIn = open(gtFile, 'r') self.cur, self.nxt = 0, 1 line_con = [[], []] id_con = [[], []] id_step = 1 a_step = head + self.a_train_set.setBuffer(head) m_step = head + self.m_train_set.setBuffer(head) if a_step != m_step: print 'Something is wrong!' print 'a_step =', a_step, ', m_step =', m_step raw_input('Continue?') while a_step < tail: # print '*********************************' a_t_gap = self.a_train_set.loadNext() m_t_gap = self.m_train_set.loadNext() if a_t_gap != m_t_gap: print 'Something is wrong!' print 'a_t_gap =', a_t_gap, ', m_t_gap =', m_t_gap raw_input('Continue?') a_step += a_t_gap m_step += m_step # print head+step, 'F', m_u_ = self.MUphi(self.m_train_set.E, self.m_train_set.V, self.Mu) # print 'Fo' a_m = self.a_train_set.m a_n = self.a_train_set.n m_m = self.m_train_set.m m_n = self.m_train_set.n if a_m != m_m or a_n != m_n: print 'Something is wrong!' print 'a_m = %d, m_m = %d' % ( a_m, m_m), ', a_n = %d, m_n = %d' % (a_n, m_n) raw_input('Continue?') # print 'm = %d, n = %d'%(m, n) if a_n == 0: print 'There is no detection in the rest of sequence!' break if id_step == 1: out = open(outFile, 'a') i = 0 while i < a_m: attrs = gtIn.readline().strip().split(',') if float(attrs[6]) >= tau_conf_score: attrs.append(1) attrs[1] = str(id_step) line = '' for attr in attrs[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 line_con[self.cur].append(attrs) id_con[self.cur].append(id_step) id_step += 1 i += 1 out.close() i = 0 while i < a_n: attrs = gtIn.readline().strip().split(',') if float(attrs[6]) >= tau_conf_score: attrs.append(1) line_con[self.nxt].append(attrs) id_con[self.nxt].append(-1) i += 1 # update the edges # print 'T', candidates = [] E_CON, V_CON = [], [] for edge in self.a_train_set.candidates: e, vs_index, vr_index = edge e = e.view(1, -1).to(self.device) vs = self.a_train_set.getApp(1, vs_index) vr = self.a_train_set.getApp(0, vr_index) e1 = self.AEphi1(e, vs, vr, self.Au) vr1 = self.AVphi(e1, vs, vr, self.Au) candidates.append((e1, vs, vr1, vs_index, vr_index)) E_CON.append(e1) V_CON.append(vs) V_CON.append(vr1) E = self.a_train_set.aggregate(E_CON).view(1, -1) V = self.a_train_set.aggregate(V_CON).view(1, -1) u1 = self.AUphi(E, V, self.Au) ret = self.a_train_set.getRet() decay_tag = [0 for i in xrange(a_m)] for i in xrange(a_m): for j in xrange(a_n): if ret[i][j] == 0: decay_tag[i] += 1 for i in xrange(len(self.a_train_set.candidates)): e1, vs, vr1, a_vs_index, a_vr_index = candidates[i] m_e, m_vs_index, m_vr_index = self.m_train_set.candidates[i] if a_vs_index != m_vs_index or a_vr_index != m_vr_index: print 'Something is wrong!' print 'a_vs_index = %d, m_vs_index = %d' % (a_vs_index, m_vs_index) print 'a_vr_index = %d, m_vr_index = %d' % (a_vr_index, m_vr_index) raw_input('Continue?') if ret[a_vs_index][a_vr_index] == tau_threshold: continue e2 = self.AEphi2(e1, vs, vr1, u1) self.a_train_set.edges[a_vs_index][a_vr_index] = e1.data.view( -1) a_tmp = F.softmax(e2) a_tmp = a_tmp.cpu().data.numpy()[0] m_e = m_e.to(self.device).view(1, -1) m_v1 = self.m_train_set.getMotion(1, m_vs_index) m_v2 = self.m_train_set.getMotion( 0, m_vr_index, m_vs_index, line_con[self.cur][m_vs_index][-1]) m_e_ = self.MEphi(m_e, m_v1, m_v2, m_u_) self.m_train_set.edges[m_vs_index][ m_vr_index] = m_e_.data.view(-1) m_tmp = F.softmax(m_e_) m_tmp = m_tmp.cpu().data.numpy()[0] t = line_con[self.cur][a_vs_index][-1] if decay_tag[a_vs_index] > 0: A = min(float(a_tmp[0]) * pow(decay, t - 1), 1.0) M = min(float(m_tmp[0]) * pow(decay, t - 1), 1.0) else: A = float(a_tmp[0]) M = float(m_tmp[0]) ret[a_vs_index][a_vr_index] = A * self.alpha + M * (1 - self.alpha) # self.a_train_set.showE(outFile) # self.m_train_set.showE(outFile) # for j in ret: # print j results = self.hungarian.compute(ret) out = open(outFile, 'a') look_up = set(j for j in xrange(a_n)) nxt = self.a_train_set.nxt for (i, j) in results: # print (i,j) if ret[i][j] >= tau_threshold: continue e1 = self.a_train_set.edges[i][j].view(1, -1).to(self.device) vs = self.a_train_set.getApp(1, i) vr = self.a_train_set.getApp(0, j) vr1 = self.AVphi(e1, vs, vr, self.Au) self.a_train_set.detections[nxt][j][0] = vr1.data look_up.remove(j) self.m_train_set.updateVelocity(i, j, line_con[self.cur][i][-1], False) id = id_con[self.cur][i] id_con[self.nxt][j] = id attr1 = line_con[self.cur][i] attr2 = line_con[self.nxt][j] # print attrs attr2[1] = str(id) if attr1[-1] > 1: # for the missing detections self.linearModel(out, attr1, attr2) line = '' for attr in attr2[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 if u_update: self.Mu = m_u_.data self.Au = u1.data for j in look_up: self.m_train_set.updateVelocity(-1, j, tag=False) for i in xrange(a_n): if id_con[self.nxt][i] == -1: id_con[self.nxt][i] = id_step attrs = line_con[self.nxt][i] attrs[1] = str(id_step) line = '' for attr in attrs[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 id_step += 1 out.close() # For missing & Occlusion index = 0 for (i, j) in results: while i != index: attrs = line_con[self.cur][index] # print '*', attrs, '*' if attrs[-1] + a_t_gap <= gap: attrs[-1] += a_t_gap line_con[self.nxt].append(attrs) id_con[self.nxt].append(id_con[self.cur][index]) self.a_train_set.moveApp(index) self.m_train_set.moveMotion(index) index += 1 if ret[i][j] >= tau_threshold: attrs = line_con[self.cur][index] # print '*', attrs, '*' if attrs[-1] + a_t_gap <= gap: attrs[-1] += a_t_gap line_con[self.nxt].append(attrs) id_con[self.nxt].append(id_con[self.cur][index]) self.a_train_set.moveApp(index) self.m_train_set.moveMotion(index) index += 1 while index < a_m: attrs = line_con[self.cur][index] # print '*', attrs, '*' if attrs[-1] + a_t_gap <= gap: attrs[-1] += a_t_gap line_con[self.nxt].append(attrs) id_con[self.nxt].append(id_con[self.cur][index]) self.a_train_set.moveApp(index) self.m_train_set.moveMotion(index) index += 1 # con = self.m_train_set.cleanEdge() # for i in xrange(len(con)-1, -1, -1): # index = con[i] # del line_con[self.nxt][index] # del id_con[self.nxt][index] line_con[self.cur] = [] id_con[self.cur] = [] # print head+step, results self.a_train_set.swapFC() self.m_train_set.swapFC() self.swapFC() gtIn.close() print ' The results:', id_step, self.bbx_counter
def compute_3rd_party_metrics(self): """ Computes the metrics defined in - Stiefelhagen 2008: Evaluating Multiple Object Tracking Performance: The CLEAR MOT Metrics MOTA, MOTAL, MOTP - Nevatia 2008: Global Data Association for Multi-Object Tracking Using Network Flows mostly_tracked/partialy_tracked/mostly_lost """ # construct Munkres object for Hungarian Method association hm = Munkres() max_cost = 1e9 # go through all frames and associate ground truth and tracker results # groundtruth and tracker contain lists for every single frame containing lists of KITTI format detections seq_gt = self.groundtruth seq_dc = self.dcareas # don't care areas seq_result_data = self.result_data seq_trajectories = defaultdict(list) seq_ignored = defaultdict(list) last_frame_ids = [[], []] for i_frame in tqdm(range(len(seq_gt))): frame_gts = seq_gt[i_frame] frame_dcs = seq_dc[i_frame] frame_results = seq_result_data[i_frame] # counting total number of ground truth and tracker objects self.n_gt += len(frame_gts) self.n_tr += len(frame_results) # use hungarian method to associate, using boxoverlap 0..1 as cost # build cost matrix cost_matrix = [] frame_ids = [[], []] # loop over ground truth objects in one frame for gt in frame_gts: # save current ids frame_ids[0].append(gt.track_id) frame_ids[1].append(-1) gt.tracker = -1 gt.id_switch = 0 gt.fragmentation = 0 cost_row = [] # loop over tracked objects in one frame for result in frame_results: # overlap == 1 means cost == 0 # Rect(cx, cy, l, w, angle) r1 = Rect(gt.cx, gt.cy, gt.l, gt.w, gt.yaw) r2 = Rect(result.cx, result.cy, result.l, result.w, result.yaw) iou = r1.intersection_over_union(r2) cost = 1 - iou # gating for boxoverlap if cost <= self.min_overlap: cost_row.append(cost) else: cost_row.append(max_cost) # = 1e9 # return cost_matrix.append(cost_row) # all ground truth trajectories are initially not associated # extend groundtruth trajectories lists (merge lists) seq_trajectories[gt.track_id].append(-1) seq_ignored[gt.track_id].append(False) if len(frame_gts) is 0: cost_matrix = [[]] # associate association_matrix = hm.compute(cost_matrix) # tmp variables for sanity checks tmptp = 0 tmpfp = 0 tmpfn = 0 # mapping for tracker ids and ground truth ids for row, col in association_matrix: # apply gating on boxoverlap c = cost_matrix[row][col] if c < max_cost: frame_gts[row].tracker = frame_results[col].track_id frame_ids[1][row] = frame_results[col].track_id frame_results[col].valid = True frame_gts[row].distance = c seq_trajectories[frame_gts[row].track_id][ -1] = frame_results[col].track_id # true positives are only valid associations self.tp += 1 tmptp += 1 else: # wrong data association frame_gts[row].tracker = -1 self.fn += 1 tmpfn += 1 # associate tracker and DontCare areas # ignore tracker in neighboring classes nignoredtracker = 0 # number of ignored tracker detections ignoredtrackers = dict() # will associate the track_id with -1 # if it is not ignored and 1 if it is # ignored; # this is used to avoid double counting ignored # cases, see the next loop # check for ignored FN/TP (truncation or neighboring object class) nignoredfn = 0 # the number of ignored false negatives nignoredtp = 0 # the number of ignored true positives gi = 0 for gt in frame_gts: if gt.tracker < 0: if gt.occlusion > self.max_occlusion or gt.truncation > self.max_truncation: seq_ignored[gt.track_id][-1] = True gt.ignored = True nignoredfn += 1 elif gt.tracker >= 0: if gt.occlusion > self.max_occlusion or gt.truncation > self.max_truncation: seq_ignored[gt.track_id][-1] = True gt.ignored = True nignoredtp += 1 gi += 1 # the below might be confusion, check the comments in __init__ # to see what the individual statistics represent # correct TP by number of ignored TP due to truncation # ignored TP are shown as tracked in visualization tmptp -= nignoredtp # count the number of ignored true positives self.itp += nignoredtp # adjust the number of ground truth objects considered self.n_gt -= (nignoredfn + nignoredtp) # count the number of ignored ground truth objects self.n_igt += nignoredfn + nignoredtp # count the number of ignored tracker objects self.n_itr += nignoredtracker # false negatives = associated gt bboxes exceding association threshold + non-associated gt bboxes tmpfn += len(frame_gts) - len(association_matrix) - nignoredfn self.fn += len(frame_gts) - len(association_matrix) - nignoredfn self.ifn += nignoredfn # false positives = tracker bboxes - associated tracker bboxes tmpfp += len(frame_results) - tmptp - nignoredtracker - nignoredtp self.fp += len( frame_results) - tmptp - nignoredtracker - nignoredtp # sanity checks # - the number of true positives minues ignored true positives # should be greater or equal to 0 # - the number of false negatives should be greater or equal to 0 # - the number of false positives needs to be greater or equal to 0 # otherwise ignored detections might be counted double # - the number of counted true positives (plus ignored ones) # and the number of counted false negatives (plus ignored ones) # should match the total number of ground truth objects # - the number of counted true positives (plus ignored ones) # and the number of counted false positives # plus the number of ignored tracker detections should # match the total number of tracker detections; note that # nignoredpairs is subtracted here to avoid double counting # of ignored detection sin nignoredtp and nignoredtracker if tmptp < 0: print(tmptp, nignoredtp) raise NameError("Something went wrong! TP is negative") if tmpfn < 0: print(tmpfn, len(frame_gts), len(association_matrix), nignoredfn, nignoredpairs) raise NameError("Something went wrong! FN is negative") if tmpfp < 0: print(tmpfp, len(frame_results), tmptp, nignoredtracker, nignoredtp, nignoredpairs) raise NameError("Something went wrong! FP is negative") if tmptp + tmpfn is not len(frame_gts) - nignoredfn - nignoredtp: print("seqidx", seq_idx) print("frame ", f) print("TP ", tmptp) print("FN ", tmpfn) print("FP ", tmpfp) print("nGT ", len(frame_gts)) print("nAss ", len(association_matrix)) print("ign GT", nignoredfn) print("ign TP", nignoredtp) raise NameError( "Something went wrong! nGroundtruth is not TP+FN") if tmptp + tmpfp + nignoredtp + nignoredtracker is not len( frame_results): print(seq_idx, f, len(frame_results), tmptp, tmpfp) print(len(association_matrix), association_matrix) raise NameError("Something went wrong! nTracker is not TP+FP") # loop over ground truth track_id # check for id switches or fragmentations for i, gt_id in enumerate(frame_ids[0]): if gt_id in last_frame_ids[0]: idx = last_frame_ids[0].index(gt_id) tid = frame_ids[1][i] lid = last_frame_ids[1][idx] if tid != lid and lid != -1 and tid != -1: if frame_gts[i].truncation < self.max_truncation: frame_gts[i].id_switch = 1 if tid != lid and lid != -1: if frame_gts[i].truncation < self.max_truncation: frame_gts[i].fragmentation = 1 # save current index last_frame_ids = frame_ids # compute mostly_tracked/partialy_tracked/mostly_lost, fragments, idswitches for all groundtruth trajectories n_ignored_tr_total = 0 if len(seq_trajectories) == 0: print("Error: There is no trajectories data") return n_ignored_tr = 0 for g, ign_g in zip(seq_trajectories.values(), seq_ignored.values()): # all frames of this gt trajectory are ignored if all(ign_g): n_ignored_tr += 1 n_ignored_tr_total += 1 continue # all frames of this gt trajectory are not assigned to any detections if all([this == -1 for this in g]): self.mostly_lost += 1 continue # compute tracked frames in trajectory last_id = g[0] # first detection (necessary to be in gt_trajectories) is always tracked tracked = 1 if g[0] >= 0 else 0 lgt = 0 if ign_g[0] else 1 for f in range(1, len(g)): if ign_g[f]: last_id = -1 continue lgt += 1 if last_id != g[f] and last_id != -1 and g[f] != -1 and g[ f - 1] != -1: self.id_switches += 1 if f < len(g) - 1 and g[f - 1] != g[f] and last_id != -1 and g[ f] != -1 and g[f + 1] != -1: self.fragments += 1 if g[f] != -1: tracked += 1 last_id = g[f] # handle last frame; tracked state is handled in for loop (g[f]!=-1) if len(g) > 1 and g[f - 1] != g[f] and last_id != -1 and g[ f] != -1 and not ign_g[f]: self.fragments += 1 # compute mostly_tracked/partialy_tracked/mostly_lost tracking_ratio = tracked / float(len(g) - sum(ign_g)) if tracking_ratio > 0.8: self.mostly_tracked += 1 elif tracking_ratio < 0.2: self.mostly_lost += 1 else: # 0.2 <= tracking_ratio <= 0.8 self.partialy_tracked += 1 if (self.n_gt_trajectories - n_ignored_tr_total) == 0: self.mostly_tracked = 0. self.partialy_tracked = 0. self.mostly_lost = 0. else: self.mostly_tracked /= float(self.n_gt_trajectories - n_ignored_tr_total) self.partialy_tracked /= float(self.n_gt_trajectories - n_ignored_tr_total) self.mostly_lost /= float(self.n_gt_trajectories - n_ignored_tr_total) # precision/recall if (self.fp + self.tp) == 0 or (self.tp + self.fn) == 0: self.recall = 0. self.precision = 0. else: self.recall = self.tp / float(self.tp + self.fn) self.precision = self.tp / float(self.fp + self.tp) return True
#Hungarian starts #%% def cost_matrix(y_pred, y, k): size_y = len(y) init_cost_mat = np.zeros((k, k)) for i in range(k): for j in range(k): bool_array = np.logical_and(y_pred == i, y == j) init_cost_mat[i][j] = np.sum(bool_array) return (1 - init_cost_mat) #%% # y_pred1 mun = Munkres() index = mun.compute(cost_matrix(y_pred1, y, n_digits)) mp = {prev: cur for (prev, cur) in index} munkres_label = np.array([mp[i] for i in y_pred1]) cnf_mat = confusion_matrix(y, munkres_label, labels=range(n_digits)) accuracy = np.trace(cnf_mat, dtype=float) / np.sum(cnf_mat) #%% # y_pred mun = Munkres() index = mun.compute(cost_matrix(y_pred, y, n_digits)) mp = {prev: cur for (prev, cur) in index} munkres_label = np.array([mp[i] for i in y_pred]) cnf_mat = confusion_matrix(y, munkres_label, labels=range(n_digits)) accuracy = np.trace(cnf_mat, dtype=float) / np.sum(cnf_mat) #%% #Spectral_Clustering_Starts
def main(): gt_file = './ground-truth/armstrong-setcore-20171009.json' # warning_dir = './cause-effect/warnings/' warning_dir = '/Users/tozammel/cause/isi-code/effect-forecasting-models/warnings_jul_sep_17/armstrong_malicious-email/' start_date = datetime.date(2017, 7, 1) end_date = datetime.date(2017, 7, 31) target_org = 'armstrong' # Potentially filter by event type # None -> Score for ALL event types # Otherwise, restrict to 'endpoint-malware', 'malicious-email', or 'malicious-destination' event_type = None # First need to parse input data warnings = load_warnings(warning_dir, target_org, event_type, start_date, end_date) events = load_gt(gt_file, target_org, event_type, start_date, end_date) print("# warnings = %d" % len(warnings)) print("# events = %d" % len(events)) # Now need to perform matching on warnings + events # To do this first have to score every possible warning-event pair # The official pair_objects.py is heavily dependent on python classes *not* provided to us by govt, so we recreate here M = Metrics() matching_matrix = np.zeros((len(events), len(warnings))) matching_dict = dict() for e_idx in range(len(events)): for w_idx in range(len(warnings)): # Check if we meet base criteria threshold if M.base_criteria(events[e_idx], warnings[w_idx]): # If so, calculate quality score pair = Pair.build(warnings[w_idx], events[e_idx], 'fake-performer', 'fake-provider') matching_matrix[e_idx, w_idx] = -pair.quality matching_dict["%d,%d" % (e_idx, w_idx)] = pair # Now do Hungarian matching munk = Munkres() pairings = munk.compute(matching_matrix.tolist()) valid_pairings = list( filter(lambda p: matching_matrix[p[0], p[1]] != 0, pairings)) nMatched = len(valid_pairings) nUnmatchedGT = len(events) - nMatched nUnmatchedW = len(warnings) - nMatched avg_qs = 0 for e_idx, w_idx in valid_pairings: # pair = matching_dict["%d,%d" % (e_idx, w_idx)] # avg_qs += pair.quality avg_qs += matching_matrix[e_idx, w_idx] avg_qs /= len(valid_pairings) avg_qs = -1 * avg_qs # calculate recall recall = nMatched / (nMatched + nUnmatchedGT) # calculate precision (Srawls: Note: comment below is straight from official code, not mine) # should these include warns and gts from the previous month? precision = nMatched / (nMatched + nUnmatchedW) print("Precision = %0.2f%%" % (100 * precision)) print("Recall = %0.2f%%" % (100 * recall)) print("Average Quality Score = %0.2f" % avg_qs) return
class AutoFormationDetector(object): """docstring for TrackingAnalysis This class for running AutoFormationDetector Args: params_dict(dict) : Dictionary of Parameters data_dict(dict) : Dictionary of Input Tracking data range_dict(dict) : Dictionary of Pitch Range """ def __init__(self, params_dict, data_dict, range_dict=None): self.__dict__ = params_dict.copy() self.data_dict = data_dict # get range_dict if not range_dict: self.range_dict = {'xmin': [], 'xmax': [], 'ymin': [], 'ymax': []} for k, data_array in self.data_dict.items(): xmin, ymin = data_array.reshape(-1, 2).min(axis=0) xmax, ymax = data_array.reshape(-1, 2).max(axis=0) self.range_dict['xmin'].append(xmin) self.range_dict['xmax'].append(xmax) self.range_dict['ymin'].append(ymin) self.range_dict['ymax'].append(ymax) self.range_dict = { k: np.min(v) if 'min' in k else np.max(v) for k, v in self.range_dict.items() } # define munk self.munk = Munkres() def compute_entropy(self, data_array): """ this module to compute entropy Args: data_array(np.ndarray) : dataset of tracking data, shape=(T, n_players, 2) Returns: - list of scipy.stats.multivariate_normal object - mean value of each position's KL-Divergence - list of KL-Divergence """ x, y = np.mgrid[ self.range_dict['xmin']:self.range_dict['xmax']:self.mesh_size, self.range_dict['ymin']:self.range_dict['ymax']:self.mesh_size] pos = np.empty(x.shape + (2, )) pos[:, :, 0] = x pos[:, :, 1] = y rv_list = [ multivariate_normal(mean=np.mean(data, axis=0), cov=np.cov(data.T)) for data in data_array ] Pn_list = [rv.pdf(pos) for rv in rv_list] P = np.mean(np.array(Pn_list), axis=0) Vn_list = [] for i, Pn in enumerate(Pn_list): Vn = entropy(Pn, P) Vn[Vn == np.inf] = 0 Vn[np.isnan(Vn)] = 0 Vn_list.append(Vn) V = np.mean(Vn_list) return rv_list, V, Pn_list def optimize_role_distribution(self, data_array, key=None): """ this module to optimize role distributions Args: key : name of data data_array(list) : shape = (T, n_players, 2) Returns: - list of optimized multivaiate_normal objects (list) """ # initialize gaussian_kde by all time frames rv_list, V, _ = self.compute_entropy(data_array.transpose(1, 0, 2)) V_pre = V attacking_direction = 'left' if 'Home' in key else 'right' if 'Away' in key else None if key: plot_formation_distribution( rv_list, os.path.join(self.fig_dir, key + '_init.png'), self.range_dict, self.mesh_size, attacking_direction) # optimize algorithm V_list = [] V_list.append(V) for _iter in range(self.n_iterations): roles_list = [] start_time = time.time() for t, data in tqdm(enumerate(data_array)): Et = np.array([[ -np.log(rv.pdf(loc)) if rv.pdf(loc) != 0 else np.inf for rv in rv_list ] for loc in data]) roles = [r_tuple[1] for r_tuple in self.munk.compute(Et)] roles_list.append(roles) data_array = np.array( [data[roles] for (data, roles) in zip(data_array, roles_list)]) # kde_list, V, _ = self.compute_entropy(data_array.transpose(1,0,2)) rv_list, V, _ = self.compute_entropy(data_array.transpose(1, 0, 2)) print('diff of V at iteration {}: {} ({} [sec])'.format( _iter, V_pre - V, time.time() - start_time)) if V_pre - V <= 0 or np.isnan(V): if _iter != 0: # kde_list = kde_list_pre rv_list = rv_list_pre break V_pre = V V_list.append(V) rv_list_pre = rv_list if key: plot_formation_distribution( rv_list, os.path.join(self.fig_dir, key + '_opt.png'), self.range_dict, self.mesh_size, attacking_direction) # save decrease of V each iterations plt.figure(figsize=(5, 3)) plt.plot(V_list) plt.xlabel('number of iterations') plt.ylabel('V') plt.savefig(os.path.join(self.fig_dir, key + '_V.png')) plt.close() return rv_list def run(self): """ this module to estimating set of role distribution, and clustering all set of role distribution to K """ # optimize role distribution for each data if self.load: print('loading role distribution ...') self.rv_dict = load_model(self.modeldir) else: print('optimizing role distribution ...') self.rv_dict = {} for n, (key, data_array) in enumerate(self.data_dict.items()): print(f'optimize -> {key} ({n+1}/{len(self.data_dict)})') rv_list = self.optimize_role_distribution(data_array, key) # self.kde_dict[key] = kde_list self.rv_dict[key] = rv_list save_model(self.rv_dict, self.modeldir) # agglomerative clustering based on EMD(=Wasserstein distance) print('Running Agglomerative Clustering of role_distribution') emd_matrix = compute_emd(list(self.rv_dict.values()), self.range_dict) agg = AgglomerativeClustering(n_clusters=self.n_clusters, affinity='precomputed', linkage='average') k_array = agg.fit_predict(emd_matrix) self.k_list = [] for i, key in enumerate(self.rv_dict.keys()): print(f'{key} = {k_array[i]}') self.k_list.append(k_array[i]) print('Plotting Clustering Results') plot_mean_formation_distribution( self.k_list, self.rv_dict, os.path.join(self.fig_dir, 'formation_clustering_results'), self.range_dict)
class GN(): def __init__(self, seq_index, tt, a, cuda=True): ''' Evaluating with the MotMetrics :param seq_index: the number of the sequence :param tt: train_test :param length: the number of frames which is used for training :param cuda: True - GPU, False - CPU ''' self.bbx_counter = 0 self.seq_index = seq_index self.hungarian = Munkres() self.device = torch.device("cuda" if cuda else "cpu") self.tt = tt self.alpha = a self.missingCounter = 0 self.sideConnection = 0 print ' Loading the model...' self.loadAModel() self.loadMModel() self.out_dir = t_dir + 'motmetrics_%s_show/' % (type) print ' ', self.out_dir if not os.path.exists(self.out_dir): os.mkdir(self.out_dir) else: deleteDir(self.out_dir) os.mkdir(self.out_dir) self.initWin() self.initOut() def initWin(self): self.color = [(255, 0, 0), (0, 255, 0), (0, 0, 255)] self.img_dir = '../MOT/MOT16/test/MOT16-%02d/img1/' % self.seq_index self.pre_win = 'Show/Previous' self.cur_win = 'Show/Current' def initOut(self): print ' Loading Data...' self.a_train_set = ADatasetFromFolder( sequence_dir, '../MOT/MOT16/test/MOT16-%02d' % self.seq_index) self.m_train_set = MDatasetFromFolder( sequence_dir, '../MOT/MOT16/test/MOT16-%02d' % self.seq_index) # gt_training = self.out_dir + 'gt_training.txt' # the gt of the training data # self.copyLines(self.seq_index, 1, gt_training, self.tt) detection_dir = self.out_dir + 'res_training_det.txt' res_training = self.out_dir + 'res_training.txt' # the result of the training data self.createTxt(detection_dir) self.createTxt(res_training) self.copyLines(self.seq_index, 1, detection_dir, self.tt, 1) self.evaluation(1, self.tt, detection_dir, res_training) def getSeqL(self, info): # get the length of the sequence f = open(info, 'r') f.readline() for line in f.readlines(): line = line.strip().split('=') if line[0] == 'seqLength': seqL = int(line[1]) f.close() return seqL def copyLines(self, seq, head, gt_seq, tail=-1, tag=0): ''' Copy the groun truth within [head, head+num] :param seq: the number of the sequence :param head: the head frame number :param tail: the number the clipped sequence :param gt_seq: the dir of the output file :return: None ''' if tt_tag: basic_dir = '../MOT/MOT%d/test/MOT%d-%02d-%s/' % (year, year, seq, type) else: basic_dir = '../MOT/MOT%d/train/MOT%d-%02d-%s/' % (year, year, seq, type) print ' Testing on', basic_dir, 'Length:', self.tt seqL = tail if tail != -1 else self.getSeqL(basic_dir + 'seqinfo.ini') det_dir = 'gt/gt_det.txt' if test_gt_det else 'det/det.txt' seq_dir = basic_dir + ('gt/gt.txt' if tag == 0 else det_dir) inStream = open(seq_dir, 'r') outStream = open(gt_seq, 'w') for line in inStream.readlines(): line = line.strip() attrs = line.split(',') f_num = int(attrs[0]) if f_num >= head and f_num <= seqL: print >> outStream, line outStream.close() inStream.close() return seqL def createTxt(self, out_file): f = open(out_file, 'w') f.close() def loadAModel(self): from mot_model import uphi, ephi if edge_initial == 0: model_dir = 'MOT' name = 'all_det_ft' i_name = 'IoU' elif edge_initial == 1: model_dir = 'Appearance' name = 'all_7_CE' i_name = 'Random' tail = 10 self.AUphi = torch.load('../%s/Results/MOT16/%s/%s/uphi_%02d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.AEphi = torch.load('../%s/Results/MOT16/%s/%s/ephi_%02d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.Au = torch.load('../%s/Results/MOT16/%s/%s/u_%02d.pth' % (model_dir, i_name, name, tail)) self.Au = self.Au.to(self.device) def loadMModel(self): from m_mot_model import uphi, ephi if edge_initial == 0: model_dir = 'MOT_Motion' name = 'all_v2_4' i_name = 'IoU' elif edge_initial == 1: model_dir = 'Motion' name = 'all_7_CE' i_name = 'Random' tail = 10 self.MUphi = torch.load('../%s/Results/MOT16/%s/%s/uphi_%d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.MEphi = torch.load('../%s/Results/MOT16/%s/%s/ephi_%d.pth' % (model_dir, i_name, name, tail)).to( self.device) self.Mu = torch.load('../%s/Results/MOT16/%s/%s/u_%d.pth' % (model_dir, i_name, name, tail)) self.Mu = self.Mu.to(self.device) def swapFC(self): self.cur = self.cur ^ self.nxt self.nxt = self.cur ^ self.nxt self.cur = self.cur ^ self.nxt def linearModel(self, out, attr1, attr2): # print 'I got you! *.*' t = attr1[-1] self.sideConnection += 1 if t > f_gap: return frame = int(attr1[0]) x1, y1, w1, h1 = float(attr1[2]), float(attr1[3]), float( attr1[4]), float(attr1[5]) x2, y2, w2, h2 = float(attr2[2]), float(attr2[3]), float( attr2[4]), float(attr2[5]) x_delta = (x2 - x1) / t y_delta = (y2 - y1) / t w_delta = (w2 - w1) / t h_delta = (h2 - h1) / 2 for i in xrange(1, t): frame += 1 x1 += x_delta y1 += y_delta w1 += w_delta h1 += h_delta attr1[0] = str(frame) attr1[2] = str(x1) attr1[3] = str(y1) attr1[4] = str(w1) attr1[5] = str(h1) line = '' for attr in attr1[:-1]: line += attr + ',' if show_recovering: line += '1' else: line = line[:-1] print >> out, line self.bbx_counter += 1 self.missingCounter += t - 1 def evaluation(self, head, tail, gtFile, outFile): ''' Evaluation on dets :param head: the head frame number :param tail: the tail frame number :param gtFile: the ground truth file name :param outFile: the name of output file :return: None ''' gtIn = open(gtFile, 'r') self.cur, self.nxt = 0, 1 imgs = [None, None] # 0 - previous img, 1 - current img going_tag = 0 # 0 - frame by frame, 1 - goto going_f line_con = [[], []] id_con = [[], []] id_step = 1 a_step = head + self.a_train_set.setBuffer(head) m_step = head + self.m_train_set.setBuffer(head) if a_step != m_step: print 'Something is wrong!' print 'a_step =', a_step, ', m_step =', m_step raw_input('Continue?') imgs[self.cur] = readImg(self.img_dir + '%06d.jpg' % a_step) going_f = a_step while a_step < tail: # print '*********************************' if going_f <= a_step: going_tag = 0 a_t_gap = self.a_train_set.loadNext() m_t_gap = self.m_train_set.loadNext() if a_t_gap != m_t_gap: print 'Something is wrong!' print 'a_t_gap =', a_t_gap, ', m_t_gap =', m_t_gap raw_input('Continue?') a_step += a_t_gap m_step += m_step # print head+step, 'F', a_u_ = self.AUphi(self.a_train_set.E, self.a_train_set.V, self.Au) m_u_ = self.MUphi(self.m_train_set.E, self.m_train_set.V, self.Mu) # print 'Fo' a_m = self.a_train_set.m a_n = self.a_train_set.n m_m = self.m_train_set.m m_n = self.m_train_set.n if a_m != m_m or a_n != m_n: print 'Something is wrong!' print 'a_m = %d, m_m = %d' % ( a_m, m_m), ', a_n = %d, m_n = %d' % (a_n, m_n) raw_input('Continue?') # print 'm = %d, n = %d'%(m, n) if a_n == 0: print 'There is no detection in the rest of sequence!' break if id_step == 1: out = open(outFile, 'a') i = 0 while i < a_m: attrs = gtIn.readline().strip().split(',') if float(attrs[6]) >= tau_conf_score: attrs.append(1) attrs[1] = str(id_step) line = '' for attr in attrs[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 # draw the rectangle x, y = int(float(attrs[2])), int(float(attrs[3])) w, h = int(float(attrs[4])), int(float(attrs[5])) cv2.rectangle(imgs[self.cur], (x, y), (x + w, y + h), self.color[0], 2) cv2.putText(imgs[self.cur], attrs[1] + '_B', (x + 3, y + 15), font, 0.6, self.color[0], 2, cv2.LINE_AA) line_con[self.cur].append(attrs) id_con[self.cur].append(id_step) id_step += 1 i += 1 out.close() print ' Frame:', a_step print id_con[self.cur] imgs[self.nxt] = readImg(self.img_dir + '%06d.jpg' % a_step) i = 0 while i < a_n: attrs = gtIn.readline().strip().split(',') if float(attrs[6]) >= tau_conf_score: # if int(attrs[0]) != a_step: # print attrs # print 'Something is Wrong! %d != %d'%(int(attrs[0]), a_step) attrs.append(1) line_con[self.nxt].append(attrs) id_con[self.nxt].append(-1) i += 1 # update the edges # print 'T', ret = self.a_train_set.getRet() for i in xrange(len(self.a_train_set.candidates)): a_e, a_vs_index, a_vr_index = self.a_train_set.candidates[i] m_e, m_vs_index, m_vr_index = self.m_train_set.candidates[i] if a_vs_index != m_vs_index or a_vr_index != m_vr_index: print 'Something is wrong!' print 'a_vs_index = %d, m_vs_index = %d' % (a_vs_index, m_vs_index) print 'a_vr_index = %d, m_vr_index = %d' % (a_vr_index, m_vr_index) raw_input('Continue?') if ret[a_vs_index][a_vr_index] == 1.0: continue a_e = a_e.to(self.device).view(1, -1) a_v1 = self.a_train_set.getApp(1, a_vs_index) a_v2 = self.a_train_set.getApp(0, a_vr_index) a_e_ = self.AEphi(a_e, a_v1, a_v2, a_u_) self.a_train_set.edges[a_vs_index][ a_vr_index] = a_e_.data.view(-1) a_tmp = F.softmax(a_e_) a_tmp = a_tmp.cpu().data.numpy()[0] m_e = m_e.to(self.device).view(1, -1) m_v1 = self.m_train_set.getMotion(1, m_vs_index) m_v2 = self.m_train_set.getMotion( 0, m_vr_index, m_vs_index, line_con[self.cur][m_vs_index][-1]) m_e_ = self.MEphi(m_e, m_v1, m_v2, m_u_) self.m_train_set.edges[m_vs_index][ m_vr_index] = m_e_.data.view(-1) m_tmp = F.softmax(m_e_) m_tmp = m_tmp.cpu().data.numpy()[0] ret[a_vs_index][a_vr_index] = float( a_tmp[0]) * self.alpha + float(m_tmp[0]) * (1 - self.alpha) # self.a_train_set.showE(outFile) # self.m_train_set.showE(outFile) # for j in ret: # print j results = self.hungarian.compute(ret) out = open(outFile, 'a') look_up = set(j for j in xrange(a_n)) for (i, j) in results: # print (i,j) if ret[i][j] >= tau_threshold: continue look_up.remove(j) self.m_train_set.updateVelocity(i, j, line_con[self.cur][i][-1], False) id = id_con[self.cur][i] id_con[self.nxt][j] = id attr1 = line_con[self.cur][i] attr2 = line_con[self.nxt][j] attr2[1] = str(id) if attr1[-1] > 1: # for the missing detections & side connection self.linearModel(out, attr1, attr2) line = '' for attr in attr2[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 if id == 23: print id_con[self.nxt][j], line_con[self.nxt][j] for j in look_up: self.m_train_set.updateVelocity(-1, j, tag=False) for i in xrange(a_n): attrs = line_con[self.nxt][i] color = self.color[1] state = '_C' if id_con[self.nxt][i] == -1: color = self.color[0] state = '_B' id_con[self.nxt][i] = id_step attrs[1] = str(id_step) line = '' for attr in attrs[:-1]: line += attr + ',' if show_recovering: line += '0' else: line = line[:-1] print >> out, line self.bbx_counter += 1 id_step += 1 # if i not in look_up: # color = self.color[2] # state = '_M' # draw the rectrangle x, y = int(float(attrs[2])), int(float(attrs[3])) w, h = int(float(attrs[4])), int(float(attrs[5])) cv2.rectangle(imgs[self.nxt], (x, y), (x + w, y + h), color, 2) cv2.putText(imgs[self.nxt], attrs[1] + state, (x + 3, y + 15), font, 0.6, color, 2, cv2.LINE_AA) out.close() # visualization cv2.imwrite(self.pre_win + '.png', imgs[self.cur]) cv2.imwrite(self.cur_win + '.png', imgs[self.nxt]) for i in xrange(a_m): if id_con[self.cur][i] == 23: print line_con[self.cur][i] break if going_tag == 0: id1, id2 = 1, 1 while id1 != -1: inp = raw_input('Input:') if ',' in inp: nums = inp.split(',') id1, id2 = int(nums[0]), int(nums[1]) if id1 != -1: id_tag = int(nums[2]) if id_tag: # t -> t-1 for i in xrange(a_n): if id_con[self.nxt][i] == id1: id1 = i break for i in xrange(a_m): if id_con[self.cur][i] == id2: id2 = i break print ret[id2][id1] else: # t-1 -> t for i in xrange(a_n): if id_con[self.cur][i] == id1: id1 = i break for i in xrange(a_m): if id_con[self.nxt][i] == id2: id2 = i break print ret[id1][id2] else: going_tag = 1 going_f = id2 else: id1 = int(inp) if id1 != -1: for i in xrange(a_n): if id_con[self.nxt][i] == id1: id1 = i break for i in xrange(a_n): if ret[i][id1] != 1: print id_con[self.cur][i], ret[i][id1] # For missing & Occlusion index = 0 for (i, j) in results: while i != index: # if a_step > 80: # print id_con[self.cur][index], line_con[self.cur][index] attrs = line_con[self.cur][index] # print '*', attrs, '*' if attrs[-1] + a_t_gap <= gap: attrs[-1] += a_t_gap line_con[self.nxt].append(attrs) id_con[self.nxt].append(id_con[self.cur][index]) self.a_train_set.moveApp(index) self.m_train_set.moveMotion(index) index += 1 if ret[i][j] >= tau_threshold: # if a_step > 80: # print id_con[self.cur][index], line_con[self.cur][index] attrs = line_con[self.cur][index] # print '*', attrs, '*' if attrs[-1] + a_t_gap <= gap: attrs[-1] += a_t_gap line_con[self.nxt].append(attrs) id_con[self.nxt].append(id_con[self.cur][index]) self.a_train_set.moveApp(index) self.m_train_set.moveMotion(index) index += 1 while index < a_m: if a_step > 80: print id_con[self.cur][index], line_con[self.cur][index] attrs = line_con[self.cur][index] # print '*', attrs, '*' if attrs[-1] + a_t_gap <= gap: attrs[-1] += a_t_gap line_con[self.nxt].append(attrs) id_con[self.nxt].append(id_con[self.cur][index]) self.a_train_set.moveApp(index) self.m_train_set.moveMotion(index) index += 1 # con = self.m_train_set.cleanEdge() # for i in xrange(len(con)-1, -1, -1): # index = con[i] # del line_con[self.nxt][index] # del id_con[self.nxt][index] line_con[self.cur] = [] id_con[self.cur] = [] cv2.imwrite('Show/%06d.png' % (a_step - 1), imgs[self.cur]) imgs[self.cur] = [] # print head+step, results self.a_train_set.swapFC() self.m_train_set.swapFC() self.swapFC() gtIn.close() print ' The results:', id_step, self.bbx_counter
def allocate(self): from debate.models import AdjudicatorAllocation # remove trainees self.adjudicators = filter(lambda a: a.score >= self.MIN_SCORE, self.adjudicators) # sort adjudicators and debates in descending score/importance self.adjudicators_sorted = list(self.adjudicators) shuffle(self.adjudicators_sorted) # randomize equally-ranked judges self.adjudicators_sorted.sort(key=lambda a: a.score, reverse=True) self.debates_sorted = list(self.debates) self.debates_sorted.sort(key=lambda a: a.importance, reverse=True) n_adjudicators = len(self.adjudicators) n_debates = len(self.debates) n_solos = n_debates - (n_adjudicators - n_debates) / 2 # get adjudicators that can adjudicate solo chairs = self.adjudicators_sorted[:n_solos] #chairs = [a for a in self.adjudicators_sorted if a.score > # self.CHAIR_CUTOFF] # get debates that will be judged by solo adjudicators chair_debates = self.debates_sorted[:len(chairs)] panel_debates = self.debates_sorted[len(chairs):] panellists = [a for a in self.adjudicators_sorted if a not in chairs] assert len(panel_debates) * 3 <= len(panellists) m = Munkres() # TODO I think "chairs" actually means "solos", rename variables if correct if len(chairs) > 0: print "costing chairs" n = len(chairs) cost_matrix = [[0] * n for i in range(n)] for i, debate in enumerate(chair_debates): for j, adj in enumerate(chairs): cost_matrix[i][j] = self.calc_cost(debate, adj) print "optimizing" indexes = m.compute(cost_matrix) total_cost = 0 for r, c in indexes: total_cost += cost_matrix[r][c] print 'total cost for solos', total_cost print 'number of solo debates', n result = ((chair_debates[i], chairs[j]) for i, j in indexes if i < len(chair_debates)) alloc = [AdjudicatorAllocation(d, c) for d, c in result] print[(a.debate, a.chair) for a in alloc] else: print "No solo adjudicators." alloc = [] # do panels n = len(panel_debates) npan = len(panellists) if npan: print "costing panellists" # matrix is square, dummy debates have cost 0 cost_matrix = [[0] * npan for i in range(npan)] for i, debate in enumerate(panel_debates): for j in range(3): # for the top half of these debates, the final panellist # can be of lower quality than the other 2 if i < npan / 2 and j == 2: adjustment = -1.0 else: adjustment = 0 for k, adj in enumerate(panellists): cost_matrix[3 * i + j][k] = self.calc_cost( debate, adj, adjustment) print "optimizing" indexes = m.compute(cost_matrix) cost = 0 for r, c in indexes: cost += cost_matrix[r][c] print 'total cost for panellists', cost # transfer the indices to the debates # the debate corresponding to row r is floor(r/3) (i.e. r // 3) p = [[] for i in range(n)] for r, c in indexes[:n * 3]: p[r // 3].append(panellists[c]) # create the corresponding adjudicator allocations, making sure # that the chair is the highest-ranked adjudicator in the panel for i, d in enumerate(panel_debates): a = AdjudicatorAllocation(d) p[i].sort(key=lambda a: a.score, reverse=True) a.chair = p[i].pop(0) a.panel = p[i] alloc.append(a) print[(a.debate, a.chair, a.panel) for a in alloc[len(chairs):]] return alloc
def main(): BANNER = ''' ████████╗██╗ ██╗███████╗ ╚══██╔══╝██║ ██║██╔════╝ ██║ ███████║█████╗ ██║ ██╔══██║██╔══╝ ██║ ██║ ██║███████╗ ╚═╝ ╚═╝ ╚═╝╚══════╝ -v1.0 by @amirootyet █████╗ ██╗ ██╗ ██████╗ ██████╗ █████╗ ████████╗ ██████╗ ██████╗ ██╔══██╗██║ ██║ ██╔═══██╗██╔════╝██╔══██╗╚══██╔══╝██╔═══██╗██╔══██╗ ███████║██║ ██║ ██║ ██║██║ ███████║ ██║ ██║ ██║██████╔╝ ██╔══██║██║ ██║ ██║ ██║██║ ██╔══██║ ██║ ██║ ██║██╔══██╗ ██║ ██║███████╗███████╗╚██████╔╝╚██████╗██║ ██║ ██║ ╚██████╔╝██║ ██║ ╚═╝ ╚═╝╚══════╝╚══════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═ ''' print(BANNER) ######################################## # Arguments to the command-line utility parser = argparse.ArgumentParser( description='A utility to manage CSE 231 TA assignment with the Munkres algorithm.') parser.add_argument("-a", "--assign", help='Find optimal (miminum cost) TA assignments.', action='store_true') parser.add_argument("-b", "--busybees", help="Find TAs that have a conflict for more than half" "of the total work slots.", action='store_true') parser.add_argument("-f", "--filename", required=True, help="CSV file containing TA preferences.") parser.add_argument("-c", "--costmatrix", help="Build and display the TA cost matrix.", action='store_true') args = parser.parse_args() ######################################### fp = open_file(args.filename) # Attempt to open the CSV file with TA preferences. time_slots, preference_dictionary = assistants_and_slots(fp) # Read time slots and preferences assistants = list(preference_dictionary.keys()) # Create a list of available TAs # Show the "busy bees"; these TAs make optimal assignment challenging. if args.busybees: busy_bees = [] for assistant, costs in preference_dictionary.items(): conflicts = costs.count(COSTS['Conflict']) # Count the conflicts for each TA. if conflicts > (len(costs)) / 2: # If the TA has more conflicts than half of the total slots. busy_bees.append((assistant, conflicts)) print("-" * 40) print("{:<20} {} (/{})".format('Busy Bee', 'Conflicts', len(costs))) print("-" * 40) for busy_bee in busy_bees: print("{:<20} {}".format(busy_bee[0], busy_bee[1])) # Build and show the cost matrix. elif args.costmatrix: cost_matrix = build_cost_matrix(preference_dictionary) # Build the cost matrix. print_matrix(cost_matrix) # Display the cost matrix. # Assign TAs the time slots / labs. elif args.assign: cost_matrix = build_cost_matrix(preference_dictionary) munkres_obj = Munkres() total = 0 indexes = munkres_obj.compute(cost_matrix) # This is where the assignment magic happens. print('{:<17s} | {:<25s} -> {:<4s}'.format('TAs', 'Assignment', 'Cost')) print("-" * 55) for row, col in indexes: cost = cost_matrix[row][col] total += cost # Calculate total cost of assignment. print('{:<17s} | {:<25s} -> {:<4d}'.format(assistants[row], time_slots[col], cost)) # Display the assignment result. for k, v in COSTS.items(): print(str(k) + " = " + str(v), end="; ") print("\nTimeslots: {}; TAs: {}".format(len(time_slots), len(assistants))) else: print("Nothing to do. See --help") fp.close() # Close the CSV file before exit.
class PeopleCounting: def __init__(self): # Array of Gallery Objects - {embeddings(numpy array), timestamp} self.identities = [] self.reid_threshold = 0.7 self.matcher = Munkres() self.timestamp = 0 def process_frame(self, frame): messages = list(frame.messages()) if len(messages) > 0: json_msg = json.loads(messages[0]) json_msg["count"] = {"people": len(self.identities)} self.timestamp = int(json_msg["timestamp"]) / 1000000000 frame.remove_message(messages[0]) frame.add_message(json.dumps(json_msg)) self.get_ids_by_embeddings(frame) return True @staticmethod def compute_reid_distance(test_embedding, reference_embedding): xx = np.dot(test_embedding, test_embedding) yy = np.dot(reference_embedding, reference_embedding) xy = np.dot(test_embedding, reference_embedding) norm = math.sqrt(xx * yy) + 1e-6 return np.float32(1.0) - xy / norm def get_ids_by_embeddings(self, frame): detected_tensors = [] detection_ids = [] detections = [x for x in frame.regions()] for i, detection in enumerate(detections): if detection.label() == "person": for j, tensor in enumerate(detection.tensors()): if tensor.name() == "face_feature" and tensor.format( ) == "cosine_distance": detected_tensors.append(tensor.data()) detection_ids.append(i) if len(detected_tensors) == 0: return if len(self.identities) == 0: for i in range(len(detected_tensors)): self.identities.append({ "embedding": copy.deepcopy(detected_tensors[i]), "timestamp": self.timestamp }) return distances = np.empty([len(detected_tensors), len(self.identities)], dtype=np.float32) for i in range(len(detected_tensors)): for j in range(len(self.identities)): distances[i][j] = PeopleCounting.compute_reid_distance( detected_tensors[i], self.identities[j]["embedding"]) matched_indexes = self.matcher.compute(distances.tolist()) matched_detections = set() for match in matched_indexes: if distances[match[0]][match[1]] <= self.reid_threshold: self.identities[match[1]]["timestamp"] = self.timestamp matched_detections.add(match[0]) for i in range(len(detected_tensors)): if i not in matched_detections: self.identities.append({ "embedding": copy.deepcopy(detected_tensors[i]), "timestamp": self.timestamp }) n = len(self.identities) i = n - 1 while i >= 0: # overdue if pass the last 5 seconds if int(self.timestamp - int(self.identities[i]["timestamp"])) > 5: self.identities[i] = self.identities[n - 1] self.identities.pop(n - 1) n -= 1 i -= 1
def testIndex(): a = [[random.random() for i in xrange(3)] for j in xrange(2)] b = Munkres() results = b.compute(a) print results