Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems with namespaces #117

Closed
Hakan-Eyilmez opened this issue Aug 6, 2024 · 5 comments
Closed

Problems with namespaces #117

Hakan-Eyilmez opened this issue Aug 6, 2024 · 5 comments
Assignees
Labels
front-end For issues where the root is mostly occurring on the front-end type:bug Bug

Comments

@Hakan-Eyilmez
Copy link

Hello,

I am currently writing a custom adapter and have encountered an issue with namespaces. In multiple instances, the model ignores the specified namespace. Below is a simple example where "Central Park" is displayed outside its namespace. Is this behavior intentional? If so, would it be possible to include a feature to toggle this on or off?

grafik
grafik

@pkgoogle
Copy link
Contributor

pkgoogle commented Aug 6, 2024

Hi @Hakan-Eyilmez, can you please provide your custom adapter and example model/graph so that we may reproduce this locally? Thanks.

@pkgoogle pkgoogle added type:bug Bug status:awaiting user response This label needs to be added to stale issues and PRs. status:more data needed This label needs to be added to stale issues and PRs. labels Aug 6, 2024
@Hakan-Eyilmez
Copy link
Author

Hello @pkgoogle, I am sorry for the inconvenience. Below I provide the code to an example adapter, which was based on your "my_adapter" adapter, with a few additions, and the graph, it produces.

my_custom_adapter
grafik

@pkgoogle pkgoogle removed status:awaiting user response This label needs to be added to stale issues and PRs. status:more data needed This label needs to be added to stale issues and PRs. labels Aug 8, 2024
@pkgoogle
Copy link
Contributor

pkgoogle commented Aug 8, 2024

Hi @Hakan-Eyilmez, thanks for the extra information, it always helps to add as much context as possible. The problem appears to be with single nodes within a namespace. I can replicate your issue with your exact adapter, but I noticed "SanFrancisco" is a layer/namespace not a node. I am able to accomplish something similar to want you want if I add an extra node within the "Cities/NewYork" layer/namespace if I incorporate it as such... example (notice I don't have a "NewYork" node):

from typing import Dict

from model_explorer import (Adapter, AdapterMetadata, ModelExplorerGraphs,
                            graph_builder)


class MyAdapter(Adapter):
  """A simple adapter that returns a hard-coded graph.

  See more info at:
  https://github.com/google-ai-edge/model-explorer/wiki/6.-Develop-Adapter-Extension
  """

  metadata = AdapterMetadata(id='my-adapter',
                             name='My first adapter',
                             description='My first adapter!',
                             source_repo='https://github.com/user/my_adapter',
                             fileExts=['test'])

  # This is required.
  def __init__(self):
    super().__init__()

  def convert(self, model_path: str, settings: Dict) -> ModelExplorerGraphs:

    # Create a graph for my road trip.
    graph = graph_builder.Graph(id='road_trip')

    ###################
    # Add nodes.

    # Create start and end node.
    #
    # They are located at root level hence the empty `namespace` parameter.
    vancouver = graph_builder.GraphNode(
        id='vancouver', label='Vancouver', namespace='')
    la = graph_builder.GraphNode(id='la', label='Los Angeles', namespace='')

    # Create a node for Seattle and put it into a 'coastal drive' layer.
    seattle = graph_builder.GraphNode(
        id='seattle', label='Seatttttle', namespace='CoastalDrive')

    # Create San Franciso as a sublayer of the CoastalDrive layer and add some
    # tourist sites there.
    sf_golden_gate_bridge = graph_builder.GraphNode(
        id='sf_golden_gate_bridge', label='Golden gate bridge',
        namespace='CoastalDrive/SanFrancisco')
    sf_pier_39 = graph_builder.GraphNode(
        id='sf_pier_39', label='PIER 39',
        namespace='CoastalDrive/SanFrancisco')

    # Create another two cities and put them into an 'inland drive' layer.
    salt_lake_city = graph_builder.GraphNode(
        id='salt_lake_city', label='Salt lake city', namespace='InlandDrive')
    las_vegas = graph_builder.GraphNode(
        id='las_vegas', label='Las Vegas', namespace='InlandDrive')
    
    # Custom nodes from Hakan
    # new_york = graph_builder.GraphNode(
    #     id='new_york', label='New York', namespace='Cities')
    central_park = graph_builder.GraphNode(
        id='central_park', label='Central Park', namespace='Cities/NewYork')
    statue_of_liberty = graph_builder.GraphNode(
        id='statue_of_liberty', label='Statue of Liberty', namespace='Cities/NewYork')

    washington = graph_builder.GraphNode(
        id='washington', label='Washington DC', namespace='Cities')

    # Add all the nodes into graph.
    graph.nodes.extend([vancouver, la, seattle, sf_golden_gate_bridge,
                        sf_pier_39, salt_lake_city, las_vegas, central_park, statue_of_liberty, washington])

    ###################
    # Add edges.

    # Connect edges along the cities for coastal drive.
    la.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='sf_pier_39'))
    sf_pier_39.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='sf_golden_gate_bridge'))
    sf_golden_gate_bridge.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='seattle'))
    seattle.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='vancouver'))

    # Connect edges along the cities for inland drive.
    #
    # LA has two incoming edges from pier_39 and las_vegas.
    # We use targetNodeInputId to identify these two edges. pier_39 goes into
    # input id '0' (default), and las_vegas goes into input id '1'.
    la.incomingEdges.append(graph_builder.IncomingEdge(
        sourceNodeId='las_vegas', targetNodeInputId='1'))
    las_vegas.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='salt_lake_city'))

    # Custom connections of City nodes
    washington.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='statue_of_liberty'))
    central_park.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='vancouver'))
    statue_of_liberty.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='central_park'))
    
    la.incomingEdges.append(graph_builder.IncomingEdge(
        sourceNodeId='washington', targetNodeInputId='2'))
    

    # Vancouver has two outgoing edges to seattle and salt_lake_city.
    # We use sourceNodeOutputId to identify these two edges. Vancouver's output
    # id '0' (default) goes to seattle, and its output id '1' goes to salt_lake_city.
    salt_lake_city.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='vancouver',
                                   sourceNodeOutputId='1'))

    #######################
    # Add node attributes.

    temperatures = ['52F', '74F', '55F', '64F', '65F', '62F', '90F', '88F', '82F', '108F']
    for i, node in enumerate(graph.nodes):
      node.attrs.append(graph_builder.KeyValue(
          key="temperature", value=temperatures[i]))

    #######################
    # Add outputs metadata.

    # This is the edge from vancouver to seattle.
    vancouver.outputsMetadata.append(graph_builder.MetadataItem(
        # This identifies which output id the metadata attached to.
        #
        # From the "add edges" section we know that output id "0" connects to
        # seattle.
        id='0',
        attrs=[graph_builder.KeyValue(key='distance', value='230 km'),
               # "__tensor_tag" is a special metadata key whose value will be
               # used as output name in side panel.
               graph_builder.KeyValue(key='__tensor_tag', value='coastal')]))

    # This is the edge from vancouver to salt_lake_city.
    vancouver.outputsMetadata.append(graph_builder.MetadataItem(
        # From the "add edges" section we know that output id "1" connects to
        # salt_lake_city.
        id='1',
        attrs=[graph_builder.KeyValue(key='distance', value='1554 km'),
               graph_builder.KeyValue(key='__tensor_tag', value='inland')]))
    
    vancouver.outputsMetadata.append(graph_builder.MetadataItem(
        # From the "add edges" section we know that output id "2" connects to
        # new_york
        id='2',
        attrs=[graph_builder.KeyValue(key='distance', value='154 km'),
               graph_builder.KeyValue(key='__tensor_tag', value='cities')]))

    # Add other distances
    def add_distance_output_metadata(from_node: graph_builder.GraphNode, distance: str):
      from_node.outputsMetadata.append(graph_builder.MetadataItem(
          id='0',
          attrs=[graph_builder.KeyValue(key='distance', value=distance)]))

    add_distance_output_metadata(salt_lake_city, '677 km')
    add_distance_output_metadata(las_vegas, '439 km')
    add_distance_output_metadata(seattle, '1310 km')
    add_distance_output_metadata(sf_golden_gate_bridge, '10 km')
    add_distance_output_metadata(sf_pier_39, '613 km')
    add_distance_output_metadata(central_park, '1490 km')
    add_distance_output_metadata(washington, '405 km')

    #######################
    # Add inputs metadata.

    la.inputsMetadata.append(graph_builder.MetadataItem(
        id='0', attrs=[graph_builder.KeyValue(key='__tensor_tag', value='coastal')]))
    la.inputsMetadata.append(graph_builder.MetadataItem(
        id='1', attrs=[graph_builder.KeyValue(key='__tensor_tag', value='inland')]))
    la.inputsMetadata.append(graph_builder.MetadataItem(
        id='2', attrs=[graph_builder.KeyValue(key='__tensor_tag', value='cities')]))

    return {'graphs': [graph]}

image

If I remove the extra node ("statue_of_liberty") It reverts to what you say:

    # Custom nodes from Hakan
    # new_york = graph_builder.GraphNode(
    #     id='new_york', label='New York', namespace='Cities')
    central_park = graph_builder.GraphNode(
        id='central_park', label='Central Park', namespace='Cities/NewYork')
    # statue_of_liberty = graph_builder.GraphNode(
    #     id='statue_of_liberty', label='Statue of Liberty', namespace='Cities/NewYork')
    ....
    # Add all the nodes into graph.
    graph.nodes.extend([vancouver, la, seattle, sf_golden_gate_bridge,
                        sf_pier_39, salt_lake_city, las_vegas, central_park, washington])
    ....
    # Custom connections of City nodes
    washington.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='central_park'))
    central_park.incomingEdges.append(
        graph_builder.IncomingEdge(sourceNodeId='vancouver'))
    # statue_of_liberty.incomingEdges.append(
    #     graph_builder.IncomingEdge(sourceNodeId='central_park'))
    
    la.incomingEdges.append(graph_builder.IncomingEdge(
        sourceNodeId='washington', targetNodeInputId='2'))

image

@jinjingforever can you please take a look at the single node issue? Thanks.

@pkgoogle pkgoogle added the front-end For issues where the root is mostly occurring on the front-end label Aug 8, 2024
@jinjingforever
Copy link
Collaborator

Hi @Hakan-Eyilmez sorry for the confusion! Model explorer would automatically remove the group/layer node if it only has one single op-node child. This is mainly for better readability. There is a setting to turn this off:

image

I will add this to the user guide and the adapter development guide. Thank you!

@jinjingforever
Copy link
Collaborator

The setting is here:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
front-end For issues where the root is mostly occurring on the front-end type:bug Bug
Projects
None yet
Development

No branches or pull requests

3 participants