graphid.core.annot_inference module¶
- graphid.core.annot_inference._rectify_decision(evidence_decision, meta_decision)[source]¶
If evidence decision is not explicitly set, then meta decision is used to make a guess. Raises a ValueError if decisions are in incompatible states.
- class graphid.core.annot_inference.Consistency[source]¶
Bases:
object
- is_consistent(cc)[source]¶
Determines if a PCC contains inconsistencies
- Parameters:
cc (set) – nodes in a PCC
- Returns:
bool: returns True unless cc contains any negative edges
- Return type:
flag
Example
>>> from graphid import demo >>> infr = demo.demodata_infr(num_pccs=1, p_incon=1) >>> assert not infr.is_consistent(next(infr.positive_components())) >>> infr = demo.demodata_infr(num_pccs=1, p_incon=0) >>> assert infr.is_consistent(next(infr.positive_components()))
- positive_components(graph=None)[source]¶
Generates the positive connected compoments (PCCs) in the graph These will contain both consistent and inconsinstent PCCs.
- Yields:
cc – set: nodes within the PCC
- class graphid.core.annot_inference.Feedback[source]¶
Bases:
object
- add_feedback_from(items, verbose=None, **kwargs)[source]¶
- Parameters:
items (List[Edge]) – each edge is a dictionary with aid1, aid2, evidence_decision, meta_decision, etc..
- add_feedback(edge, evidence_decision=None, tags=None, user_id=None, meta_decision=None, confidence=None, timestamp_c1=None, timestamp_c2=None, timestamp_s1=None, timestamp=None, verbose=None, priority=None)[source]¶
Primary method for adding feedback and review edges to the graph.
- Parameters:
edge (tuple) – an undirected edge represented as a pair of aids
evidence_decision (str) – decision made based on visual evidence between the two photos. Can be POSTV, NEGTV, INCMP, or UNKWN. Note: POSTV etc… are the variables not the strings.
tags (list of str) – additional information to specify
user_id (str) – who is doing this review. This can identify a human or algorithm reviewer (e.g. ‘user:joncrall’ or ‘algo:vamp’).
meta_decision (str) – decision made based on external knowledge. Perhaps the photographer knows that two animals are the same because all photos are of the same animal. This constrains the identity problem, but does not impact the computer vision learning algorithms, which aren’t given the info needed to make this sort of decision.
confidence (str) – how sure is the user of this decision.
timestamp_c1 (int) – Time that the review client started
timestamp_c2 (int) – Time that the review client ended
timestamp_s1 (int) – Time that the review server started
timestamp (int) – Time that the review server ended
verbose (bool) – verbosity
priority (float, optional) – the priority assigned to this edge before review. This is only relevant for the termination criterion.
Notes
If infr.params[‘inference.enabled’] is True, then the edge is inserted into the graph and its properties are updated dynamically. Otherwise it is only added to the internal feedback dictionary and the apply_feedback_edges method must be called.
Example
>>> from graphid import demo >>> infr = demo.demodata_infr(num_pccs=5) >>> infr.add_feedback((5, 6), POSTV) >>> infr.add_feedback((5, 6), NEGTV, tags=['photobomb']) >>> infr.add_feedback((1, 2), INCMP) >>> print(ub.urepr(infr.internal_feedback, nl=3, sk=1)) >>> assert len(infr.external_feedback) == 0 >>> assert len(infr.internal_feedback) == 2 >>> assert len(infr.internal_feedback[(5, 6)]) == 2 >>> assert len(infr.internal_feedback[(1, 2)]) == 1
- feedback_keys = ['evidence_decision', 'tags', 'user_id', 'meta_decision', 'timestamp_c1', 'timestamp_c2', 'timestamp_s1', 'timestamp', 'confidence', 'num_reviews', 'review_id']¶
- feedback_data_keys = ['evidence_decision', 'tags', 'user_id', 'meta_decision', 'timestamp_c1', 'timestamp_c2', 'timestamp_s1', 'timestamp', 'confidence']¶
- apply_feedback_edges()[source]¶
Transforms the feedback dictionaries into nx graph edge attributes. This
- reset(state='empty')[source]¶
Removes all edges from graph and resets name labels.
Example
>>> from graphid.core.annot_inference import * # NOQA >>> from graphid import demo >>> infr = demo.demodata_infr(num_pccs=5) >>> assert len(list(infr.edges())) > 0 >>> infr.reset(state='empty') >>> assert len(list(infr.edges())) == 0
- class graphid.core.annot_inference.NameRelabel[source]¶
Bases:
object
- _rectify_names(old_names, new_labels)[source]¶
Finds the best assignment of old names based on the new groups each is assigned to.
old_names = [None, None, None, 1, 2, 3, 3, 4, 4, 4, 5, None] new_labels = [ 1, 2, 2, 3, 4, 5, 5, 6, 3, 3, 7, 7]
- relabel_using_reviews(graph=None, rectify=True)[source]¶
Relabels nodes in graph based on positive connected components
This will change the ‘name_label’ of the nodes to be consistent while preserving any existing names as best as possible. If rectify=False, this will be faster, but the old names may not be preserved and each PCC will be assigned an arbitrary name.
Note
if something messes up you can call infr.reset_labels_to_ibeis() to reset node labels to their original values — this will almost always put the graph in an inconsistent state — but then you can this with rectify=True to fix everything up.
- Parameters:
graph (nx.Graph, optional) – only edges in graph are relabeled defaults to current graph.
rectify (bool, optional) – if True names attempt to remain consistent otherwise there are no restrictions on name labels other than that they are distinct.
Example
>>> from graphid import demo, util >>> infr = demo.demodata_infr(num_pccs=5, pos_redun=1) >>> names0 = set(infr.get_node_attrs('name_label').values()) >>> infr.relabel_using_reviews(rectify=True) >>> names1 = set(infr.get_node_attrs('name_label').values()) >>> assert names0 == names1 >>> # wont change because its the entire graph >>> #infr.relabel_using_reviews(rectify=False) >>> #names2 = set(infr.get_node_attrs('name_label').values())
- class graphid.core.annot_inference.MiscHelpers[source]¶
Bases:
object
- remove_aids(aids)[source]¶
Remove annotations from the graph.
- Returns:
split: indicates which PCCs were split by this action.
- Return type:
Note
This may cause unintended splits!
CommandLine
xdoctest -m graphid.core.annot_inference MiscHelpers.remove_aids
Example
>>> from graphid import demo, util >>> infr = demo.demodata_infr(num_pccs=5, pos_redun=1) >>> infr.refresh_candidate_edges() >>> infr.pin_node_layout() >>> before = infr.copy() >>> aids = infr.aids[::5] >>> splits = infr.remove_aids(aids) >>> assert len(splits['old']) > 0 >>> infr.assert_invariants() >>> # xdoc: +REQUIRES(--show) >>> util.qtensure() >>> after = infr >>> before.show(fnum=1, pnum=(1, 2, 1), pickable=True) >>> after.show(fnum=1, pnum=(1, 2, 2), pickable=True)
- add_aids(aids, nids=None)[source]¶
CommandLine
python -m graphid.core.annot_inference MiscHelpers.add_aids
Doctest
>>> aids_ = [1, 2, 3, 4, 5, 6, 7, 9] >>> infr = AnnotInference(aids=aids_, autoinit=True) >>> aids = [2, 22, 7, 9, 8] >>> nids = None >>> infr.add_aids(aids, nids) >>> result = infr.aids >>> print(result) >>> assert len(infr.graph) == len(infr.aids) [1, 2, 3, 4, 5, 6, 7, 9, 22, 8]
- class graphid.core.annot_inference.AltConstructors[source]¶
Bases:
object
- classmethod from_netx(G, verbose=False, infer=True)[source]¶
Creates an AnnotInference object from a networkx graph
- status(extended=False)[source]¶
Returns information about the state of the graph.
- Parameters:
extended (bool) – if True, adds in extra information that requires an O(|E|) amount of computation, otherwise only O(1) stats that are dynamically tracked are returned.
- Returns:
- a dictionary containing status information. Each of the keys
represents the following information:
nNodes: number of nodes in the graph nEdges: number of edges in the graph nCCs: number of positive connected components nPostvEdges: number of edges labeled as positive nNegtvEdges: number of edges labeled as negative nIncmpEdges: number of edges labeled as incomparable nUnrevEdges: number of edges labeled as unreviewed nPosRedunCCs: the number of PCCs which are currently
k-positive-redundant, i.e. we are confident those PCCs are the same individual.
- nNegRedunPairs: the number of PCCs pairs which are
currently k-negative-redundant, i.e. we are confident those PCCs are different individuals.
- nInconsistentCCs: the number of inconsistent PCCs that need
to be fixed, i.e. the number of PCCs with an internal negative edges.
- If extended is True, then the following keys are also present
nNegEdgesWithin: number of negatives edges inside PCCs nNegEdgesBetween: number of negative edges between PCCs nIncompEdgesWithin: number of incomparable edges inside PCCs nIncompEdgesBetween: number of incomparable edges between PCCs nUnrevEdgesWithin: number of unreviewed edges inside PCCs nUrevEdgesBetween: number of unreviewed edges between PCCs
- Return type:
Example
>>> from graphid import demo >>> infr = demo.demodata_infr(num_pccs=5, p_incon=0.5, pcc_size=10) >>> print(ub.urepr(infr.status(extended=True))) { 'nNodes': 50, 'nEdges': 93, 'nCCs': 5, 'nPostvEdges': 66, 'nNegtvEdges': 10, 'nIncmpEdges': 2, 'nUnrevEdges': 15, 'nPosRedunCCs': 1, 'nNegRedunPairs': 2, 'nInconsistentCCs': 3, 'nNegEdgesWithin': 4, 'nNegEdgesBetween': 6, 'nIncompEdgesWithin': 0, 'nIncompEdgesBetween': 2, 'nUnrevEdgesWithin': 15, 'nUrevEdgesBetween': 0, }
- class graphid.core.annot_inference.AnnotInference(aids=[], nids=None, autoinit=True, verbose=False)[source]¶
Bases:
NiceRepr
,AltConstructors
,MiscHelpers
,Feedback
,NameRelabel
,Consistency
,NonDynamicUpdate
,Recovery
,DynamicUpdate
,Redundancy
,Priority
,AssertInvariants
,DummyEdges
,Convenience
,AttrAccess
,SimulationHelpers
,InfrReviewers
,InfrLoops
,InfrCallbacks
,InfrCandidates
,GraphVisualization
class for maintaining state of an identification
CommandLine
python -m graphid.core.annot_inference AnnotInference python -m graphid.core.annot_inference AnnotInference --show
Example
>>> from graphid.core import AnnotInference >>> import pytest >>> infr = AnnotInference() >>> print('infr = {}'.format(infr)) infr = <AnnotInference(nNodes=0, nEdges=0, nCCs=0)> >>> infr.add_aids(list(range(1, 6))) >>> print('infr = {}'.format(infr)) infr = <AnnotInference(nNodes=5, nEdges=0, nCCs=5)> >>> # Add some feedback >>> infr.params['allow_unseen_nodes'] = False >>> infr.add_feedback((1, 2), POSTV) >>> infr.add_feedback((1, 3), INCMP) >>> infr.add_feedback((1, 4), NEGTV) >>> with pytest.raises(ValueError): >>> infr.add_feedback((1, 10), NEGTV) >>> with pytest.raises(ValueError): >>> infr.add_feedback((11, 12), NEGTV) >>> print('infr = {}'.format(infr)) infr = <AnnotInference(nNodes=5, nEdges=3, nCCs=4)> >>> # xdoc: +REQUIRES(--show) >>> infr.show_graph() >>> util.show_if_requested()
- subparams(prefix)[source]¶
Returns dict of params prefixed with <prefix>. The returned dict does not contain the prefix
Example
>>> infr = AnnotInference() >>> result = ub.urepr(infr.subparams('refresh'), nl=0, precision=1, sort=1) >>> print(result) {'method': 'binomial', 'patience': 72, 'thresh': 0.1, 'window': 20}