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

feat: InterpretationAgent #42

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
8 changes: 8 additions & 0 deletions kb/use_problem_solving_method_module/probability.gwf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<GWF version="2.0">
<staticSector>
<node type="node/const/perm/group" idtf="probability" shapeColor="0" id="2026135622960" parent="0" left="0" top="0" right="70" bottom="25" textColor="164" text_angle="0" text_font="Times New Roman" font_size="10" x="261" y="327" haveBus="false" idtf_pos="0">
<content type="0" mime_type="" content_visibility="false" file_name=""/>
</node>
</staticSector>
</GWF>
44 changes: 44 additions & 0 deletions kb/use_problem_solving_method_module/startup_test.gwf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<GWF version="2.0">
<staticSector>
<node type="node/const/perm/group" idtf="action_use_problem_solving_method" shapeColor="193" id="1700868619024" parent="0" left="0" top="0" right="216" bottom="25" textColor="164" text_angle="0" text_font="Times New Roman" font_size="10" x="631.5" y="388.728" haveBus="false" idtf_pos="0">
<content type="0" mime_type="" content_visibility="false" file_name=""/>
</node>
<node type="node/const/perm/group" idtf="question" shapeColor="0" id="1700868615904" parent="0" left="0" top="0" right="55" bottom="25" textColor="164" text_angle="0" text_font="Times New Roman" font_size="10" x="559.84" y="469.5" haveBus="false" idtf_pos="0">
<content type="0" mime_type="" content_visibility="false" file_name=""/>
</node>
<node type="node/const/perm/struct" idtf="Problem_classify_image" shapeColor="0" id="1700868618608" parent="0" left="0" top="0" right="144" bottom="25" textColor="164" text_angle="0" text_font="Times New Roman" font_size="10" x="604" y="649" haveBus="false" idtf_pos="1">
<content type="0" mime_type="" content_visibility="false" file_name=""/>
</node>
<node type="node/const/perm/struct" idtf="Image_classificator" shapeColor="0" id="1700868615072" parent="0" left="0" top="0" right="118" bottom="25" textColor="164" text_angle="0" text_font="Times New Roman" font_size="10" x="723" y="650" haveBus="false" idtf_pos="0">
<content type="0" mime_type="" content_visibility="false" file_name=""/>
</node>
<node type="node/const/perm/role" idtf="rrel_2" shapeColor="0" id="1700868619440" parent="0" left="0" top="0" right="42" bottom="25" textColor="164" text_angle="0" text_font="Times New Roman" font_size="10" x="752" y="570" haveBus="false" idtf_pos="0">
<content type="0" mime_type="" content_visibility="false" file_name=""/>
</node>
<node type="node/const/perm/role" idtf="rrel_1" shapeColor="0" id="1700865690096" parent="0" left="0" top="0" right="42" bottom="25" textColor="164" text_angle="0" text_font="Times New Roman" font_size="10" x="590" y="560" haveBus="false" idtf_pos="1">
<content type="0" mime_type="" content_visibility="false" file_name=""/>
</node>
<node type="node/const/perm/general" idtf="interpretation_test" shapeColor="0" id="1700865694256" parent="0" left="0" top="0" right="112" bottom="25" textColor="164" text_angle="0" text_font="Times New Roman" font_size="10" x="664" y="515" haveBus="false" idtf_pos="0">
<content type="0" mime_type="" content_visibility="false" file_name=""/>
</node>
<pair type="pair/const/pos/perm/orient/membership" idtf="" shapeColor="0" id="1700869326368" parent="0" id_b="1700868619024" id_e="1700865694256" b_x="631.5" b_y="388.728" e_x="664" e_y="515" dotBBalance="0" dotEBalance="0">
<points/>
</pair>
<pair type="pair/const/pos/perm/orient/membership" idtf="" shapeColor="0" id="1700869323728" parent="0" id_b="1700868615904" id_e="1700865694256" b_x="559.84" b_y="469.5" e_x="664" e_y="515" dotBBalance="0" dotEBalance="0">
<points/>
</pair>
<pair type="pair/const/pos/perm/orient/membership" idtf="" shapeColor="0" id="1700869323248" parent="0" id_b="1700865694256" id_e="1700868618608" b_x="664" b_y="515" e_x="604" e_y="649" dotBBalance="0" dotEBalance="0">
<points/>
</pair>
<pair type="pair/const/pos/perm/orient/membership" idtf="" shapeColor="0" id="1700869320368" parent="0" id_b="1700865690096" id_e="1700869323248" b_x="590" b_y="560" e_x="0" e_y="0" dotBBalance="0" dotEBalance="0.582799">
<points/>
</pair>
<pair type="pair/const/pos/perm/orient/membership" idtf="" shapeColor="0" id="1700869326848" parent="0" id_b="1700865694256" id_e="1700868615072" b_x="664" b_y="515" e_x="723" e_y="650" dotBBalance="0" dotEBalance="0">
<points/>
</pair>
<pair type="pair/const/pos/perm/orient/membership" idtf="" shapeColor="0" id="1700869320608" parent="0" id_b="1700868619440" id_e="1700869326848" b_x="752" b_y="570" e_x="0" e_y="0" dotBBalance="0" dotEBalance="0.564765">
<points/>
</pair>
</staticSector>
</GWF>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from typing import List

from modules.UseProblemSolvingMethodModule.converters import Converter


class ConverterUser:
def __init__(self, problems:List[str]):
self.problems = problems.sort()

def __findConverter(self)->Converter:
for problem in self.problems:
match problem:
case "concept_image_classification":
pass

Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import logging
from os.path import dirname, abspath
from typing import List

import PIL.Image
import numpy

import numpy as np
import sc_kpm
from sc_client.client import *
from sc_client.constants import sc_types
from sc_client.models import *
import tensorflow as tf

from modules.UseProblemSolvingMethodModule.dataClasses.InterpretationParameters import InterpretationParameters
from modules.UseProblemSolvingMethodModule.dataClasses.AnnStruct import AnnStruct
from modules.UseProblemSolvingMethodModule.dataClasses.inputOutput.ImageStruct import Image

logging.basicConfig(
level=logging.INFO, format="%(asctime)s | %(name)s | %(message)s", datefmt="[%d-%b-%y %H:%M:%S]"
)

# todo: use absolute filepaths?
def get_ann_path() -> str:
script_directory = dirname(dirname(abspath(__file__)))
ann_path = dirname(dirname(dirname(dirname(dirname(script_directory)))))
return ann_path


class InterpretationParametersReader:
def __init__(self) -> None:
pass

def get_interpretation_parameters(self, action_addr: ScAddr) -> InterpretationParameters:
ann_address = self.__get_ann_address(action_addr)

ann_model = self.__get_keras_model(ann_address)
ann_input_shape = self.__get_ann_input_shape(ann_address)
ann_output_shape = self.__get_ann_output_shape(ann_address)

ann_struct = AnnStruct(network_address=ann_address,
ann_model=ann_model,
num_of_inputs=ann_input_shape,
num_of_outputs=ann_output_shape)

problem_addr = self.__get_problem_addr(action_addr)
input_struct = self.__get_image(self.__get_image_addr(problem_addr))

return InterpretationParameters(ann_struct, input_struct)

@staticmethod
def __get_rrel_target(source_addr: ScAddr, rrel_name: str) -> ScAddr:
template = ScTemplate()
template.triple_with_relation(
source_addr,
sc_types.EDGE_ACCESS_VAR_POS_PERM,
sc_types.NODE_VAR,
sc_types.EDGE_ACCESS_VAR_POS_PERM,
sc_kpm.ScKeynodes[rrel_name]
)
return template_search(template)[0][2]

@staticmethod
def __get_nrel_target_link(source_addr: ScAddr, nrel_name: str) -> ScAddr:
template = ScTemplate()
template.triple_with_relation(
source_addr,
sc_types.EDGE_D_COMMON_VAR,
sc_types.LINK_VAR,
sc_types.EDGE_ACCESS_VAR_POS_PERM,
sc_kpm.ScKeynodes[nrel_name]
)
return template_search(template)[0][2]

# def __get_classes(source_addr: ScAddr) -> List[ScAddr]:
# template = ScTemplate()
# template.triple(
# sc_types.NODE_CLASS,
# sc_types.EDGE_ACCESS_VAR_POS_PERM,
# source_addr
# )
#
# sc_classes = []
# for template_result in template_search(template):
# sc_classes.append(template_result[2])
# return sc_classes

def __get_problem_addr(self, action_addr: ScAddr) -> ScAddr:
return self.__get_rrel_target(action_addr, "rrel_1")

# def __get_problem_types(self, problem_addr: ScAddr) -> List[ScAddr]:
# return self.__get_classes(problem_addr)

def __get_image_addr(self, problem_addr: ScAddr) -> ScAddr:
return self.__get_rrel_target(problem_addr, "rrel_input_image")

def __get_file(self, file_addr: ScAddr, nrel_name: str) -> str:
filepath_link_addr = self.__get_nrel_target_link(file_addr, nrel_name)
file_filepath = get_link_content(filepath_link_addr)[0].data
return file_filepath

def __get_image(self, image_addr: ScAddr) -> Image:
image_path = self.__get_file(image_addr, "nrel_filepath")
kb_path = f'{get_ann_path()}/kb'

image = PIL.Image.open(f'{kb_path}/{image_path}')
image_struct = Image(object_addr=image_addr,
data_array=numpy.array(image),
image_shape=image.size)
logging.info(f'Image imported')
return image_struct

def __get_ann_address(self, action_addr: ScAddr) -> ScAddr:
return self.__get_rrel_target(action_addr, "rrel_2")

def __get_keras_model(self, model_addr: ScAddr) -> tf.keras.Model:
ann_path = self.__get_file(model_addr, "nrel_keras_ann")
kb_path = f'{get_ann_path()}/kb'

model = tf.keras.models.load_model(f"{kb_path}/{ann_path}")
return model

def __get_ann_input_shape(self, ann_addr: ScAddr) -> int:
model = self.__get_keras_model(ann_addr)
logging.info(f"Input shape: {model.input_shape[1]}")
return model.input_shape[1]

def __get_ann_output_shape(self, ann_addr: ScAddr) -> int:
model = self.__get_keras_model(ann_addr)
logging.info(f"Output shape: {model.output_shape[1]}")
return model.output_shape[1]

Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import sc_kpm
from sc_client.client import create_elements, template_search, resolve_keynodes
from sc_client.constants import sc_types
from sc_client.constants.common import ScEventType
from sc_client.models import ScAddr, ScTemplate, ScConstruction, ScIdtfResolveParams
from sc_kpm import ScAgentClassic, ScKeynodes
from sc_kpm.sc_result import ScResult
from sc_kpm.utils import get_system_idtf, create_node, create_edge, get_link_content_data
import tensorflow as tf
import numpy

from modules.UseProblemSolvingMethodModule.annInterpreter.InterpretationParametersReader import \
InterpretationParametersReader
from modules.UseProblemSolvingMethodModule.converters.ImageConverter import ImageConverter

from modules.UseProblemSolvingMethodModule.dataClasses.InterpretationParameters import InterpretationParameters



class UseProblemSolvingMethodAgent(ScAgentClassic):
def __init__(self) -> None:
super().__init__("action_use_problem_solving_method")

def on_event(self, event_element: ScAddr, event_edge: ScAddr, action_element: ScAddr) -> ScResult:
self.logger.info("UseProblemSolvingMethodAgent started")
result = self.__run(action_element)
self.logger.info("UseProblemSolvingAgent finished")
return result

def __run(self, action_element: ScAddr) -> ScResult:
# Get Interpretation parameters from input struct
reader = InterpretationParametersReader()
interpretation_parameters: InterpretationParameters = reader.get_interpretation_parameters(action_element)

model = interpretation_parameters.ann_struct.ann_model
input_data = ImageConverter.convert_image_to_inputs(interpretation_parameters.input_struct,
interpretation_parameters.ann_struct.num_of_inputs)

predictions = model.predict(input_data)
score = tf.nn.softmax(predictions[0])
print(numpy.max(score * 100))
self.logger.info(f"Object score:{score}")

self.__save_ann_output(predictions, interpretation_parameters)

output_construct = ScConstruction()
output_construct.create_edge(sc_type=sc_types.EDGE_D_COMMON_CONST,
src=action_element,
trg=interpretation_parameters.input_struct.object_addr,
alias='edge')
output_construct.create_edge(sc_types.EDGE_ACCESS_CONST_POS_PERM,
sc_kpm.ScKeynodes["nrel_result"],
'edge')
addresses = create_elements(output_construct)
assert all(addresses)

return ScResult.OK

def __save_ann_output(self, predictions: numpy.array, interpretation_parameters: InterpretationParameters) -> None:
objet_addr = interpretation_parameters.input_struct.object_addr

score = tf.nn.softmax(predictions[0])
max_prediction: int = numpy.max(score * 100)
max_prediction_index: int = int(numpy.argmax(score * 100))
self.__save_ann_output_to_sc_memory(max_prediction, max_prediction_index, objet_addr)

def __save_ann_output_to_sc_memory(self, max_prediction: int, max_prediction_index: int,
object_addr: ScAddr) -> None:
self.logger.info(f"Max prediction: {max_prediction}")

# TODO add ann classes if exists
# Now it name recognised class as index of output array
result_node_params = ScIdtfResolveParams(idtf=f'[{max_prediction_index}]', type=sc_types.NODE_CONST_CLASS)
result_node_addr = resolve_keynodes(result_node_params)[0]
construction = ScConstruction()
construction.create_edge(sc_type=sc_types.EDGE_ACCESS_CONST_FUZ_PERM,
src=result_node_addr,
trg=object_addr,
alias='fuz_edge')
addresses = create_elements(construction)
assert len(addresses) == 1
assert all(addresses)
fuz_edge_addr = addresses[0]
self.logger.info(f'Fuz Edge addr:{fuz_edge_addr}')

probability_node_params = ScIdtfResolveParams(idtf=f'{str(max_prediction)}%', type=sc_types.NODE_CONST_CLASS)
probability_node_addr = resolve_keynodes(probability_node_params)[0]
probability_construction = ScConstruction()
probability_construction.create_edge(sc_type=sc_types.EDGE_ACCESS_CONST_POS_PERM,
src=sc_kpm.ScKeynodes["probability"],
trg=probability_node_addr, )
probability_construction.create_edge(sc_type=sc_types.EDGE_ACCESS_CONST_POS_PERM,
src=probability_node_addr,
trg=fuz_edge_addr)
addresses = create_elements(probability_construction)
assert len(addresses) == 2
assert all(addresses)
# fuz_edge_addr = addresses[0]
self.logger.info(f'Probability created')

self.logger.info(f"Saved to kb")
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from sc_kpm import ScModule

from .UseProblemSolvingMethodAgent import UseProblemSolvingMethodAgent


class UseProblemSolvingMethodModule(ScModule):
def __init__(self) -> None:
super().__init__(UseProblemSolvingMethodAgent())
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Converter:
def __init__(self):
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import numpy

from .Converter import Converter
from modules.UseProblemSolvingMethodModule.dataClasses.inputOutput.ImageStruct import Image


class ImageConverter(Converter):
@staticmethod
def convert_image_to_inputs(image: Image, number_of_inputs: int) -> numpy.array:
numpydata = image.data_array
numpy.shape(numpydata)

numpydata = numpy.reshape(numpydata, (1, number_of_inputs))
return numpydata
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from dataclasses import dataclass
from typing import List

import keras
from sc_client.models import ScAddr


@dataclass
class AnnStruct:
network_address: ScAddr
ann_model: keras.Model
num_of_inputs: int
num_of_outputs: int
output_labels: List[str] = None
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from dataclasses import dataclass
from typing import List

from sc_client.models import ScAddr

from .AnnStruct import AnnStruct
from .inputOutput.ImageStruct import Image


@dataclass
class InterpretationParameters:
ann_struct: AnnStruct
input_struct: Image # inputs for ann
problem_types: List[ScAddr] = None # todo or maybe unused


Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from dataclasses import dataclass
from .InputOutputStruct import InputOutput

import numpy as np


@dataclass
class Image(InputOutput):
# data_array: np.array
image_shape: tuple = None
label: str = None
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from dataclasses import dataclass

import numpy as np
from sc_client.models import ScAddr


@dataclass
class InputOutput:
object_addr: ScAddr
data_array: np.array
Loading
Loading