def make_test_similarity(test_case): #toy_params = { # True: {'mu': 0.9, 'sigma': .1}, # False: {'mu': 0.1, 'sigma': .4} #} # tau = np.pi * 2 from ibeis import constants as const # view_to_ori = const.VIEWTEXT_TO_YAW_RADIANS view_to_ori = ut.map_dict_keys(lambda x: const.YAWALIAS[x], const.VIEWTEXT_TO_YAW_RADIANS) # view_to_ori = { # 'F': -1 * tau / 4, # 'L': 0 * tau / 4, # 'B': 1 * tau / 4, # 'R': 2 * tau / 4, # } import vtool as vt nid_list = np.array(ut.dict_take_column(test_case, 'name')) yaw_list = np.array(ut.dict_take(view_to_ori, ut.dict_take_column(test_case, 'view'))) rng = np.random.RandomState(0) pmat = [] for idx in range(len(test_case)): nid = nid_list[idx] yaw = yaw_list[idx] p_same = nid == nid_list p_comp = 1 - vt.ori_distance(yaw_list, yaw) / np.pi # estimate noisy measurements p_same_m = np.clip(p_same + rng.normal(0, .5, size=len(p_same)), 0, .9) p_comp_m = np.clip(p_comp + rng.normal(0, .5, size=len(p_comp)), 0, .9) # p_same_and_comp = p_same_m * p_comp_m pmat.append(p_same_and_comp) # P = np.array(pmat) P[np.diag_indices(len(P))] = 0 P = P + P.T / 2 P = np.clip(P, .01, .99) print(ut.hz_str(' P = ', ut.array_repr2(P, precision=2, max_line_width=140))) return P
def draw_em_graph(P, Pn, PL, gam, num_labels): """ python -m ibeis.algo.hots.testem test_em --show --no-cnn """ num_labels = PL.shape[1] name_nodes = ['N%d' % x for x in list(range(1, num_labels + 1))] #annot_nodes = ut.chr_range(len(Pn), base='A') annot_nodes = ['X%d' % x for x in list(range(1, len(Pn) + 1))] # name_nodes = ut.chr_range(num_labels, base='A') nodes = name_nodes + annot_nodes PL2 = gam[:, num_labels:].T PL2 += .01 PL2 = PL2 / PL2.sum(axis=1)[:, None] # PL2 = PL2 / np.linalg.norm(PL2, axis=0) zero_part = np.zeros((num_labels, len(Pn) + num_labels)) prob_part = np.hstack([PL2, Pn]) print(ut.hz_str(' PL2 = ', ut.array_repr2(PL2, precision=2))) # Redo p with posteriors if ut.get_argflag('--postem'): P = np.vstack([zero_part, prob_part]) weight_matrix = P # NOQA graph = ut.nx_from_matrix(P, nodes=nodes) graph = graph.to_directed() # delete graph dup_edges = [] seen_ = set([]) for u, v in graph.edges(): if u < v: u, v = v, u if (u, v) not in seen_: seen_.add((u, v)) else: dup_edges.append((u, v)) graph.remove_edges_from(dup_edges) import plottool as pt import networkx as nx if len(name_nodes) == 3 and len(annot_nodes) == 4: graph.node[annot_nodes[0]]['pos'] = (20., 200.) graph.node[annot_nodes[1]]['pos'] = (220., 200.) graph.node[annot_nodes[2]]['pos'] = (20., 100.) graph.node[annot_nodes[3]]['pos'] = (220., 100.) graph.node[name_nodes[0]]['pos'] = (10., 300.) graph.node[name_nodes[1]]['pos'] = (120., 300.) graph.node[name_nodes[2]]['pos'] = (230., 300.) nx.set_node_attributes(graph, 'pin', 'true') print('annot_nodes = %r' % (annot_nodes,)) print('name_nodes = %r' % (name_nodes,)) for u in annot_nodes: for v in name_nodes: if graph.has_edge(u, v): print('1) u, v = %r' % ((u, v),)) graph.edge[u][v]['taillabel'] = graph.edge[u][v]['label'] graph.edge[u][v]['color'] = pt.ORANGE graph.edge[u][v]['labelcolor'] = pt.BLUE del graph.edge[u][v]['label'] elif graph.has_edge(v, u): print('2) u, v = %r' % ((u, v),)) graph.edge[v][u]['headlabel'] = graph.edge[v][u]['label'] graph.edge[v][u]['color'] = pt.ORANGE graph.edge[v][u]['labelcolor'] = pt.BLUE del graph.edge[v][u]['label'] else: print((u, v)) print('!!') # import itertools # name_const_edges = [(u, v, {'style': 'invis'}) for u, v in itertools.combinations(name_nodes, 2)] # graph.add_edges_from(name_const_edges) # nx.set_edge_attributes(graph, 'constraint', {edge: False for edge in graph.edges() if edge[0] == 'b' or edge[1] == 'b'}) # nx.set_edge_attributes(graph, 'constraint', {edge: False for edge in graph.edges() if edge[0] in annot_nodes and edge[1] in annot_nodes}) # nx.set_edge_attributes(graph, 'constraint', {edge: True for edge in graph.edges() if edge[0] in name_nodes or edge[1] in name_nodes}) # nx.set_edge_attributes(graph, 'constraint', {edge: True for edge in graph.edges() if (edge[0] in ['a', 'b'] and edge[1] in ['a', 'b']) and edge[0] in annot_nodes and edge[1] in annot_nodes}) # nx.set_edge_attributes(graph, 'constraint', {edge: True for edge in graph.edges() if (edge[0] in ['c'] or edge[1] in ['c']) and edge[0] in annot_nodes and edge[1] in annot_nodes}) # nx.set_edge_attributes(graph, 'constraint', {edge: True for edge in graph.edges() if (edge[0] in ['a'] or edge[1] in ['a']) and edge[0] in annot_nodes and edge[1] in annot_nodes}) # nx.set_edge_attributes(graph, 'constraint', {edge: True for edge in graph.edges() if (edge[0] in ['b'] or edge[1] in ['b']) and edge[0] in annot_nodes and edge[1] in annot_nodes}) # graph.add_edges_from([('root', n) for n in nodes]) # {node: 'names' for node in name_nodes}) nx.set_node_attributes(graph, 'color', {node: pt.RED for node in name_nodes}) # nx.set_node_attributes(graph, 'width', {node: 20 for node in nodes}) # nx.set_node_attributes(graph, 'height', {node: 20 for node in nodes}) #nx.set_node_attributes(graph, 'group', {node: 'names' for node in name_nodes}) #nx.set_node_attributes(graph, 'group', {node: 'annots' for node in annot_nodes}) nx.set_node_attributes(graph, 'groupid', {node: 'names' for node in name_nodes}) nx.set_node_attributes(graph, 'groupid', {node: 'annots' for node in annot_nodes}) graph.graph['clusterrank'] = 'local' # graph.graph['groupattrs'] = { # 'names': {'rankdir': 'LR', 'rank': 'source'}, # 'annots': {'rankdir': 'TB', 'rank': 'source'}, # } ut.nx_delete_edge_attr(graph, 'weight') # pt.show_nx(graph, fontsize=10, layoutkw={'splines': 'spline', 'prog': 'dot', 'sep': 2.0}, verbose=1) layoutkw = { # 'rankdir': 'LR', 'splines': 'spline', # 'splines': 'ortho', # 'splines': 'curved', # 'compound': 'True', # 'prog': 'dot', 'prog': 'neato', # 'packMode': 'clust', # 'sep': 4, # 'nodesep': 1, # 'ranksep': 1, } #pt.show_nx(graph, fontsize=12, layoutkw=layoutkw, verbose=0, as_directed=False) pt.show_nx(graph, fontsize=6, fontname='Ubuntu', layoutkw=layoutkw, verbose=0, as_directed=False) pt.interactions.zoom_factory()
def test_em(): """ CommandLine: python -m ibeis.algo.hots.testem test_em --show python -m ibeis.algo.hots.testem test_em --show --no-cnn Example: >>> # DISABLE_DOCTEST >>> from ibeis.algo.hots.testem import * # NOQA >>> P, Pn, PL, gam, num_labels = test_em() >>> ut.quit_if_noshow() >>> import plottool as pt >>> pt.qt4ensure() >>> draw_em_graph(P, Pn, PL, gam, num_labels) >>> ut.show_if_requested() """ print('EM') # Matrix if unary probabilites, The probability that each node takes on a # given label, independent of its edges. test_case = [ {'name': 1, 'view': 'L'}, {'name': 1, 'view': 'L'}, {'name': 2, 'view': 'L'}, {'name': 2, 'view': 'R'}, {'name': 2, 'view': 'B'}, {'name': 3, 'view': 'L'}, #{'name': 3, 'view': 'L'}, #{'name': 4, 'view': 'L'}, ] def make_test_similarity(test_case): #toy_params = { # True: {'mu': 0.9, 'sigma': .1}, # False: {'mu': 0.1, 'sigma': .4} #} # tau = np.pi * 2 from ibeis import constants as const # view_to_ori = const.VIEWTEXT_TO_YAW_RADIANS view_to_ori = ut.map_dict_keys(lambda x: const.YAWALIAS[x], const.VIEWTEXT_TO_YAW_RADIANS) # view_to_ori = { # 'F': -1 * tau / 4, # 'L': 0 * tau / 4, # 'B': 1 * tau / 4, # 'R': 2 * tau / 4, # } import vtool as vt nid_list = np.array(ut.dict_take_column(test_case, 'name')) yaw_list = np.array(ut.dict_take(view_to_ori, ut.dict_take_column(test_case, 'view'))) rng = np.random.RandomState(0) pmat = [] for idx in range(len(test_case)): nid = nid_list[idx] yaw = yaw_list[idx] p_same = nid == nid_list p_comp = 1 - vt.ori_distance(yaw_list, yaw) / np.pi # estimate noisy measurements p_same_m = np.clip(p_same + rng.normal(0, .5, size=len(p_same)), 0, .9) p_comp_m = np.clip(p_comp + rng.normal(0, .5, size=len(p_comp)), 0, .9) # p_same_and_comp = p_same_m * p_comp_m pmat.append(p_same_and_comp) # P = np.array(pmat) P[np.diag_indices(len(P))] = 0 P = P + P.T / 2 P = np.clip(P, .01, .99) print(ut.hz_str(' P = ', ut.array_repr2(P, precision=2, max_line_width=140))) return P Pn = make_test_similarity(test_case) if False: Pn = np.array(np.matrix( b""" .0 .7 .3 .2 .4 .5; .7 .0 .4 .4 .3 .5; .3 .4 .0 .6 .1 .5; .2 .4 .6 .0 .2 .3; .4 .3 .1 .2 .0 .8; .5 .5 .5 .3 .8 .0 """)) PL = np.array(np.matrix( b""" .7 .5 .5; .8 .4 .3; .5 .7 .3; .5 .8 .4; .3 .2 .8; .5 .5 .8 """)) if True: Pn = np.array(np.matrix( b""" 1.0 0.7 0.4 0.2; 0.7 1.0 0.4 0.4; 0.4 0.4 1.0 0.6; 0.2 0.4 0.6 1.0 """)) PL = np.array(np.matrix( b""" 0.7 0.5 0.5; 0.8 0.4 0.3; 0.5 0.7 0.3; 0.5 0.8 0.4 """)) num_nodes = Pn.shape[0] for num_labels in range(1, 2): #Pn = np.array(np.matrix( # b""" # .0 .7 .3 .2 .4 .5; # .7 .0 .4 .4 .3 .5; # .3 .4 .0 .6 .1 .5; # .2 .4 .6 .0 .2 .3; # .4 .3 .1 .2 .0 .8; # .5 .5 .5 .3 .8 .0 # """)) # Uniform distribution over labels if 0: PL = np.ones((num_nodes, num_labels)) / num_labels # Give nodes preferences PL[np.diag_indices(num_labels)] *= 1.01 PL /= np.linalg.norm(PL, axis=0) # PL[0, :] = .01 / (num_labels - 1) # PL[0, 0] = .99 else: PL /= np.linalg.norm(PL, axis=0) # Number of nodes num_nodes = Pn.shape[0] # Number of classes num_labels = PL.shape[1] #num_labels = num_nodes #if 0 or num_labels != 3: # PL = np.ones((num_nodes, num_labels)) / num_labels # # PL[0, :] = .01 / (num_labels - 1) # # PL[0, 0] = .99 d = num_labels + num_nodes # Stack everything into a single matrix zero_part = np.zeros((num_labels, num_nodes + num_labels)) prob_part = np.hstack([PL, Pn]) #print(ut.hz_str(' prob_part = ', ut.array_repr2(prob_part[:, :], precision=2))) P = np.vstack([zero_part, prob_part]) # Gamma will hold a probability distribution over the nodes # The labeled nodes must match themselves. # The unlabeld nodes are initialized with a uniform distribution. gam = np.hstack([np.eye(num_labels), np.ones((num_labels, num_nodes)) / num_labels]) print('Initialize') print('num_labels = %r' % (num_labels,)) # print(ut.hz_str(' gamma = ', ut.array_repr2(gam[:, num_labels:], max_line_width=140, precision=2))) print(ut.hz_str(' gamma = ', ut.array_repr2(gam, max_line_width=140, precision=2))) delta_i = np.zeros(num_labels) def dErr(i, gam, P, delta_i=delta_i): # exepcted liklihood is cross entropy error delta_i[:] = 0 # Compute the gradient of the cross entropy error # This is over both names and annotations for j in range(d): if i != j: delta_i += gam[:, j] * np.log(P[i, j] / (1 - P[i, j])) # compute the projected gradient delta_i_hat = delta_i - delta_i.sum() / num_labels return delta_i_hat # Maximies the expected liklihood of gamma learn_rate = 0.05 num_iters = 1000 dGam = np.zeros(gam.shape) # for count in range(num_iters): for count in ut.ProgIter(range(num_iters), label='EM', bs=True): # Compute error gradient for i in range(num_labels, d): dGam[:, i] = dErr(i, gam, P) # Make a step in the gradient direction # print(ut.hz_str(' dGam = ', ut.array_repr2(dGam, max_line_width=140, precision=2))) gam = gam + learn_rate * dGam # Normalize gam = np.clip(gam, 0, 1) for i in range(num_labels, d): gam[:, i] = gam[:, i] / np.sum(gam[:, i]) # print(ut.hz_str(' gamma = ', ut.array_repr2(gam, max_line_width=140, precision=2))) # print(ut.hz_str(' gamma = ', ut.array_repr2(gam[:, num_labels:], max_line_width=140, precision=2))) print('Finished') return P, Pn, PL, gam, num_labels