3 matplotlib.use(
"TkAgg")
4 import matplotlib.pyplot
as plt
10 from os.path
import isfile, join, isdir
19 from ConfigParser
import SafeConfigParser
26 """Model management and supervisor 29 Single point of entry for managing training and interaction with multiple models running in parallel. Parameters loaded from `default.ini` in `samSupervisor` context folder which contains the configuration details for samSupervisor as seen in the example below. 32 root_path /usr/local/SAM_Data_Models 33 config_path sensory_level_conf.ini 40 controllerIP 127.0.0.1 43 root_path : Path to folder containing Data and Models folders. 44 config_path : Name of configuration file detailing parameters for different drivers. 45 persistence : `'True'` or `'False'` indicating terminals opened by samSupervisor stay open even after process termination. 46 windowed : `'True'` or `'False'` indicating separate terminals will be opened by samSupervisor for each training and interaction process. 47 verbose : `'True'` or `'False'` switching on or off logging to stdout. 48 useOPC : `'True'` or `'False'` indicating using or not using OPC for further information. 49 startModels : `'True'` or `'False'` indicating all models in the config_path file will be automatically loaded during samSupervisor startup. 50 acceptableDelay : String with an integer for the number of tries before a model is declared dead, aborted and restarted. 51 controllerIP : IP address for the ipyparallel controller. Currently not in use. Leave at 127.0.0.1. 55 yarp.RFModule.__init__(self)
104 Configure interactionSAMModel Yarp module. 107 rf: Yarp RF context input. 110 Boolean indicating success or no success in initialising the Yarp module. 112 self.
rootPath = rf.find(
"root_path").asString()
117 while os.path.isfile(loggerFName)
and os.path.getsize(loggerFName) > 0:
121 logFormatter = logging.Formatter(
"%(asctime)s [%(name)-33s] [%(levelname)8s] %(message)s")
123 rootLogger = logging.getLogger(
'samSupervisor')
124 rootLogger.setLevel(logging.DEBUG)
126 fileHandler = logging.FileHandler(loggerFName)
127 fileHandler.setFormatter(logFormatter)
128 rootLogger.addHandler(fileHandler)
130 consoleHandler = logging.StreamHandler()
131 consoleHandler.setFormatter(logFormatter)
132 rootLogger.addHandler(consoleHandler)
133 logging.root = rootLogger
135 logging.info(loggerFName)
137 yarpAvailable = yarp.Network.checkNetwork()
138 if not yarpAvailable:
142 (getattr(signal, n), n)
for n
in dir(signal)
if n.startswith(
'SIG')
and '_' not in n)
145 proc = subprocess.Popen([
'yarp',
'ping',
'/sam/rpc:i'], stdout=subprocess.PIPE)
146 output = proc.stdout.read()
151 logging.error(
'samSupervisor already running. /sam/rpc:i port present')
154 rootPath = rf.check(
"root_path")
155 interactionConfPath = rf.check(
"config_path")
157 if not interactionConfPath
and not rootPath:
158 logging.error(
"Cannot find .ini settings")
162 persistence = rf.check(
"persistence", yarp.Value(
"False")).asString()
163 useOPC = rf.check(
"useOPC", yarp.Value(
"False")).asString()
164 acceptableDelay = rf.check(
"acceptableDelay", yarp.Value(
"5")).asString()
165 windowed = rf.check(
"windowed", yarp.Value(
"True")).asString()
166 verbose = rf.check(
"verbose", yarp.Value(
"True")).asString()
167 startModels = rf.check(
"startModels", yarp.Value(
"True")).asString()
168 controllerIP = rf.check(
"controllerIP", yarp.Value(
"None")).asString()
170 nodesGroupString = rf.findGroup(
'nodes').toString()
171 logging.info(
'nodesGroupString length: ' + str(len(nodesGroupString)))
172 if len(nodesGroupString) > 7:
173 nodesList = nodesGroupString.replace(
'"',
'').replace(
')',
'').split(
' (')[1:]
177 if utils.RepresentsInt(t[1]):
178 nodesDict[t[0]] = int(t[1])
181 for j
in nodesDict.keys():
182 lenList.append(len(j))
184 nodeMaxLen = max(lenList)
189 self.
persistence =
True if(persistence ==
"True")
else False 190 self.
windowed =
True if(windowed ==
"True")
else False 191 self.
verbose =
True if(verbose ==
"True")
else False 192 self.
useOPC =
True if (useOPC ==
"True")
else False 194 if int(acceptableDelay) > 5:
197 logging.info(
'Requested responsive delay = ' + str(int(acceptableDelay)) +
' Minimum allowed = 5')
204 logging.info(
'Root supervisor path: \t' + str(self.
rootPath))
206 logging.info(
'Bash Persistence set to: \t' + str(self.
persistence))
207 logging.info(
'Windowed set to: \t' + str(self.
windowed))
208 logging.info(
'Verbose set to: \t' + str(self.
verbose))
209 logging.info(
'Controller IP: \t' + str(controllerIP))
210 logging.info(
'Nodes:')
211 if len(nodesDict) > 0:
212 for j
in nodesDict.keys():
213 logging.info(
' \t', j.ljust(nodeMaxLen+4) +str(nodesDict[j]))
232 self.
devnull = open(
'/dev/null',
'w')
237 logging.info(out.toString())
244 self.
opcPort = yarp.RpcClient()
271 rfModel = yarp.ResourceFinder()
272 rfModel.setVerbose(self.
verbose)
273 rfModel.setDefaultContext(
"samSupervisor")
289 command = yarp.Bottle()
290 command.addString(
"load")
293 logging.info(command.toString())
294 reply = yarp.Bottle()
298 logging.info(reply.toString())
299 logging.info(
"-----------------------------------------------")
302 logging.info(
'Config ready. Awaiting input ...')
305 logging.info(
"Models available for training.")
309 logging.info(
"No available models to load or train")
319 Starts by issuing an `EXIT` command to all loaded interaction modules. Terminates training processes. Closes samSupervisor ports and terminates cluster if one has been started. 325 Boolean indicating success or no success in closing the Yarp module. 342 v.send_signal(signal.SIGINT)
346 v[4].send_signal(signal.SIGINT)
350 self.
cluster.terminateProcesses()
354 Check model availabilities 357 This function starts by compiling a list of models present in the `root_path/Models`. Then cross checks that the corresponding data folder exists in `root_path/Data` and that it contains an appropriate `config.ini` file. If a data folder exists but a model does not, this is added to __noModels__ list. If the folder and the model both exist and the modification date of the data is newer than that of the model it is added to __updateModels__ (requiring an update) if the modification date of the model is newer it is added to __uptodateModels__. If the model exists but not the data folder config file, the model is ignored. Each model and data folder pair is then paired with its respective driver from the SAM_Drivers folder. If a corresponding driver is not available, the data and model are ignored. 360 reply : Yarp Bottle containing a many string formatted response to indicate the state of all the available drivers and the corresponding models. 370 self.
modelsList = [s.replace(
".pickle",
"")
for s
in onlyfiles
371 if ".pickle" in s
and '~' not in s
and '__L' not in s]
373 logging.info(
'Models available: ' +
', '.join(self.
modelsList))
376 dataList = [f
for f
in listdir(self.
dataPath)
if isdir(join(self.
dataPath, f))]
378 logging.info(
"Data folders available: " +
', '.join(dataList))
387 for importer, modname, ispkg
in pkgutil.iter_modules(SAM.SAM_Drivers.__path__):
388 if 'SAMDriver_' in modname:
393 logging.info(
"Training functions available: " +
', '.join(self.
functionsList))
397 model_params = [
"model_options"]
399 logging.info(
'-------------------')
400 logging.info(
'Finding trainable data ...')
405 logging.error(
"No training functions found. Exiting ...")
413 logging.info(
"Checking " + loc +
" ...")
415 parser = SafeConfigParser()
416 found = parser.read(loc +
"/config.ini")
419 logging.warning(
"config.ini not found for " + str(f))
422 if parser.has_section(model_params[0]):
425 trainOptions = parser.get(model_params[0],
'driver').split(
',')
429 availableFuncs = [s
for s
in trainOptions
for g
in self.
functionsList if s == g]
430 if len(availableFuncs) != 0:
432 logging.info(
"Training functions for data " + f +
" are " +
','.join(trainOptions))
433 logging.info(
"Corresponding functions available: " +
','.join(availableFuncs))
435 if len(availableFuncs) > 1:
437 logging.info(
"The first function will be chosen: " + availableFuncs[0])
441 for dirName, dirs, filenames
in os.walk(loc):
442 t.append(os.path.getmtime(dirName))
445 logging.info(
"Data folder last modified: %s" % time.ctime(lastMod))
451 logging.warning(
"Training functions for data " + f + \
452 " not found. Will not train " + f)
454 logging.warning(
"No option 'driver' in section: 'model_options' for " + f)
457 logging.warning(
"Training parameters for data " + f +
" not found. Will not train " \
458 + f +
"\nCheck config.ini is formatted correctly")
464 logging.info(
'-------------------')
465 logging.info(
'Checking corresponding models')
473 if str(f[0]) +
'_' in g
and '~' not in g:
478 t.append(os.path.getmtime(loc))
482 currModelsDict = dict()
483 currModelsDict[
'exp'] =
'' 484 currModelsDict[
'best'] =
'' 485 currModelsDict[
'backup'] =
'' 487 tempModel = currModels[t.index(l)]
488 if 'exp' in tempModel:
489 currModelsDict[
'exp'] = tempModel
490 elif 'best' in tempModel:
491 currModelsDict[
'best'] = tempModel
492 elif 'backup' in tempModel:
493 currModelsDict[
'backup'] = tempModel
500 logging.info(str(f[0]) +
" Model last modified: %s" % time.ctime(lastMod))
502 tdiff = datetime.datetime.fromtimestamp(f[2]).replace(microsecond=0) - \
503 datetime.datetime.fromtimestamp(lastMod).replace(microsecond=0)
505 logging.info(str(f[0]) +
' Model outdated by ' + str(tdiff) +
'. Will be trained')
508 logging.info(str(f[0]) +
' Model up-to-date')
513 logging.info(str(f[0]) +
' Model not found. Training Required')
517 logging.info(
'-------------------')
531 reply.addVocab(yarp.Vocab_encode(
"many"))
540 cmd.addString(
'check')
543 a = str(rep.toString())
548 def respond(self, command, reply):
550 Respond to external requests 553 Available requests \n 554 1) __askOPC__ : Query the OPC for additional contextual data. calls askOPC() \n 555 2) __attentionModulation <>__ : Modulate attention of all models. Enable classification if <param> is `continue`. Disable classification if <param> is `stop`. Calls attentionModulation() \n 556 3) __check_all__ : Cross checks available models, data folders, config files and driver availability. Calls checkAvailabilities() \n 557 4) __check <modelName>__ : Cross check available models, data folders, config files and driver availability for a specific <modelName>. Calls checkModel()\n 558 5) __config <modelName>__ : Opens the data folder config file for the specific <modelName> to view or change the training parameters. Calls configModel() \n 559 6) __dataDir <modelName>__ : Returns the model filename that will be used for the specific <modelName>. Calls dataDirModel() \n 560 7) __delete <modelName>__ : Deletes model from hard disk. Calls deleteModel() \n 561 8) __help__ : Returns a many formatted list of available commands \n 562 9) __load <modelName>__ : Launches interactionSAMModel.py for the <modelName>. Calls loadModel() \n 563 10) __close <modelName>__ : Terminates the interactionSAMModel.py process for the <modelName>. Calls closeModel() \n 564 11) __optimise <modelName>__ : Launches samOptimiser.py to optimise the training of the specified model. Calls optimise().\n 565 12) __quit__ : Closes all loaded models and stops samSupervisor.\n 566 13) __report <modelName> <plotFlag>__ : Reports the confusion matrix of <modelName> if it is a trained model. Plot result if <plotFlag> is set to `plot`. Return a formatted confusion matrix if <plotFlag> is not `plot`. Calls reportModel()\n 567 14) __train <modelName>__ : Launches trainSAMModel.py to train the specified model. Calls train() \n 568 15) __list_callSigns__ : Returns a list of the `ask_X_label` and `ask_X_instance` call signs for all models that are currently loaded with interactionSAMModel.py\n 569 7) __ask_X_label__ : Forwards the received ask label request to the corresponding loaded model if the callsign is present in __list_callsigns__. This command has an enforced timeout of 10 seconds to respond otherwise returns `nack`. \n 570 8) __ask_X_instance__ : Forwards the received ask instance request to the corresponding loaded model if the callsign is present in __list_callsigns__. This command has an enforced timeout of 10 seconds to respond otherwise returns `nack`. \n 573 command : Incoming Yarp bottle containing external request. 574 reply : Outgoing Yarp bottle containing reply to processed request. 577 Boolean indicating success or no success in responding to external requests. 579 helpMessage = [
"Commands are: ",
"\taskOPC",
"\tattentionModulation mode",
"\tcheck_all",
"\tcheck modelName",
580 "\tclose modelName",
"\tconfig modelName",
"\tdataDir modelName",
"\tdelete modelName",
"\thelp",
581 "\tlistModels mode",
"\tload modelName",
"\toptimise modelName",
"\tquit",
"\treport modelName",
"\ttrain modelName",
587 if command.get(0).asString() ==
"askOPC":
589 elif command.get(0).asString() ==
"attentionModulation":
591 elif command.get(0).asString() ==
"check_all":
593 elif command.get(0).asString() ==
"check":
595 elif command.get(0).asString() ==
"listModels":
597 elif command.get(0).asString() ==
"close":
599 elif command.get(0).asString() ==
"delete":
601 elif command.get(0).asString() ==
"report":
603 elif command.get(0).asString() ==
"dataDir":
605 elif command.get(0).asString() ==
"config":
607 elif command.get(0).asString() ==
"help":
608 reply.addVocab(yarp.Vocab_encode(
"many"))
609 for i
in helpMessage:
611 elif command.get(0).asString() ==
"load":
613 elif command.get(0).asString() ==
"quit":
614 reply.addString(
"quitting")
616 elif command.get(0).asString() ==
"train":
617 self.
train(reply, command)
618 elif command.get(0).asString() ==
"optimise":
620 elif command.get(0).asString() ==
"list_callSigns":
621 reply.addVocab(yarp.Vocab_encode(
"many"))
623 repStr = str(e[0]) +
" Model: \t" 625 repStr += str(f) +
"\t" 626 reply.addString(repStr)
628 elif any(command.get(0).asString()
in e[3]
for e
in self.
rpcConnections):
629 if 'instance' in command.get(0).asString()
and command.size() != 2:
630 reply.addString(
"Instance name required. e.g. ask_face_instance Daniel")
634 if reply.size() == 0:
635 reply.addString(
'nack')
636 reply.addString(
'No response')
637 except utils.TimeoutError:
638 reply.addString(
'nack')
639 reply.addString(
'Failed to respond within timeout')
642 reply.addString(
"nack")
643 reply.addString(
"Wrong command")
659 Helper function to forward a call sign to the respective model with an enforced timeout of 10 seconds for the reply so the module does not hang. 662 command : Yarp bottle with the call sign. 663 reply : Yarp bottle for the reply from the model. 669 if command.get(0).asString()
in e[3]:
670 e[1].write(command, reply)
674 Module interrupt logic. 676 Returns : Boolean indicating success of logic or not. 681 """ Returns lists of models for train or interaction categpories. 684 command : Yarp bottle with command. Example valid commands below. 685 reply : Yarp bottle for the reply from the model. 688 Boolean indicating success or not. 691 listModels train - returns list of models that require training\n 692 listModels interaction - returns list of interaction ready models\n 693 listModels all - returns a list of all models 696 logging.info(command.toString())
701 if command.size() < 2:
702 reply.addString(
"nack")
703 reply.addString(
"'train', 'interaction' or `all` required. eg listModels train")
704 elif command.get(1).asString()
not in [
"train",
"interaction",
"all"]:
705 reply.addString(
"nack")
706 reply.addString(
"'train', 'interaction' or `all` required. eg listModels train")
708 if command.get(1).asString() ==
"train":
710 elif command.get(1).asString() ==
"interaction":
712 elif command.get(1).asString() ==
"all":
715 reply.addString(
"ack")
716 for j
in listOfModels:
722 """ Modulate attention of all models. 725 command : Yarp bottle with command. Example valid commands below. 726 reply : Yarp bottle for the reply from the model. 729 Boolean indicating success or not. 732 attentionModulation stop \n 733 attentionModulation continue 737 logging.info(command.toString())
738 if command.size() < 2:
739 reply.addString(
"nack")
740 reply.addString(
"'stop' or 'continue' required. eg attentionModulation stop")
742 reply.addString(
"nack")
743 reply.addString(
"'stop' or 'continue' required. eg attentionModulation stop")
748 cmd.addString(
'attention')
749 cmd.addString(command.get(1).asString())
751 reply.addString(
'ack')
755 """ Query the OPC for additional contextual data. 758 Query name of agent from OPC and forward it to Actions model if it is loaded. This is currently the only model that uses this method. Method will be generalised in future versions. 761 reply : Yarp bottle for the reply from OPC. 764 Boolean indicating success or not. 770 if self.
opcPort.getOutputCount() == 0:
773 if self.
opcPort.getOutputCount() > 0:
774 if len(actionsLoadedList) > 0:
777 cmd.fromString(
'[ask] (("entity" "==" "agent"))')
782 lID = rep.get(1).toString().split(
'(')[-1].replace(
')',
'').split(
' ')
788 cmd.fromString(
'[get] (("id" ' + str(j) +
') (propSet ("name")))')
791 agentList.append(rep.toString().split(
'name')[-1].split(
')')[0].replace(
' ',
''))
793 currAgent = [t
for t
in agentList
if t !=
'icub']
795 if len(currAgent) != 0:
796 currAgent = currAgent[0]
797 if len(currAgent) > 0:
798 for j
in actionsLoadedList:
800 cmd.addString(
'information')
801 cmd.addString(
'partnerName')
802 cmd.addString(currAgent)
806 reply.addString(
'ack')
807 reply.addString(
'Agent = ' + str(currAgent))
809 reply.addString(
'nack')
810 reply.addString(
'No agent apart from icub present')
812 reply.addString(
'nack')
813 reply.addString(
'No agent apart from icub present')
815 reply.addString(
'ack')
816 reply.addString(
'No actions loaded')
818 reply.addString(
'nack')
819 reply.addString(
'OPC port not present')
820 logging.warning(
'OPC not found!')
824 def closeModel(self, reply, command, external=False):
825 """ Close a loaded model. 828 Check that a model has been loaded and if it is close the loaded model. 831 reply : Yarp bottle for the reply from the function. 832 command : Yarp bottle with the command and the model name to close. 833 external: Boolean indicating model to be closed is to be closed for good if `True`. Else model is to be closed for restart. 836 Boolean indicating success or not. 838 if command.size() != 2:
839 reply.addString(
'nack')
840 reply.addString(
"Model name required. e.g. close Actions")
849 logging.info(
"Already open = " + str(alreadyOpen))
851 logging.info(command.get(1).asString())
865 reply.addString(
'ack')
866 reply.addString(command.get(1).asString() +
" model closed.")
868 reply.addString(
'ack')
869 reply.addString(command.get(1).asString() +
" model is not running.")
873 """ Load a trained model 876 Launches interactionSAMModel.py for the model mentioned in the command. 879 reply : Yarp bottle for the reply from the function. 880 command : Yarp bottle with the command and the model name to load. 885 parser = SafeConfigParser()
887 if command.size() < 2:
888 reply.addString(
'nack')
889 reply.addString(
"Model name required. e.g. load Actions")
891 reply.addString(
'nack')
892 reply.addString(
"Cannot load model. Model training available but not yet trained.")
894 ret = parser.read(join(self.
dataPath, command.get(1).asString(),
"config.ini"))
900 if parser.has_option(
'model_options',
'driver')
and parser.has_option(
'model_options',
'modelNameBase'):
901 interactionFunction = parser.get(
'model_options',
'driver').split(
',')
904 interactionFunction = [s
for s
in interactionFunction
for g
in self.
functionsList if s == g]
905 if len(interactionFunction) != 0:
906 j = [s
for s
in self.
trainableModels if s[0] == command.get(1).asString()][0]
909 callSignList = self.
interactionParser.get(j[0],
'callSign').replace(
' ',
'').split(
',')
913 correctOperation =
False 920 logging.info(
"Loading " + str(interfacePortName) +
" with " + str(callSignList))
923 logging.info(
"Model already open")
926 correctOperation = correctOp_check1
and correctOp_check2
927 if not correctOp_check2
and correctOp_check1:
931 logging.info(
"correct operation = " + str(correctOperation))
935 logging.info(
"Model not open")
937 if alreadyOpen
and correctOperation:
940 cmd.addString(
"reload")
943 if rep.get(0).asString() ==
'ack':
944 reply.addString(
'ack')
945 reply.addString(command.get(1).asString() +
" model re-loaded correctly")
947 reply.addString(
'nack')
948 reply.addString(command.get(1).asString() +
" model did not re-loaded correctly")
949 elif alreadyOpen
and not correctOperation:
954 cmd.addString(
"close")
955 cmd.addString(command.get(1).asString())
957 reply.addString(
'ack')
958 reply.addString(command.get(1).asString() +
" model terminated ")
961 interfacePort = yarp.RpcClient()
962 successfulOpen = interfacePort.open(interfacePortName)
964 if not successfulOpen:
965 logging.error(
'CRAP')
975 modType = command.get(2).asString()
976 if modType !=
'' and modType
in j[4].keys():
977 if j[4][modType] !=
'':
978 modToLoad = j[4][modType]
981 if j[4][modType] !=
'':
982 modToLoad = j[4][modType]
983 logging.info(str(modType) +
' ' + str(modToLoad))
987 cmd =
'interactionSAMModel.py ' + args
991 logging.info(
"cmd = " + str(cmd))
994 command =
"bash -c \"" + cmd +
"; exec bash\"" 996 command =
"bash -c \"" + cmd +
"\"" 999 c = subprocess.Popen([self.
terminal,
'-e', command], shell=
False)
1001 c = subprocess.Popen([cmd], shell=
True)
1003 self.
rpcConnections.append([j[0], interfacePort, interfacePortName[:-1], callSignList, c,
'loading'])
1025 reply.addString(
'nack')
1026 reply.addString(
"Failure to load " + str(interactionFunction[0]) +
" model")
1029 cmd.addString(
"close")
1034 logging.info(
'pinging portNames to ' + str(self.
rpcConnections[-1][0]))
1037 cmd.addString(
"portNames")
1040 logging.info(
'ping received ' + str(rep.toString()))
1044 if rep.size() > 1
and rep.get(0).asString() ==
'ack':
1045 for p
in range(rep.size()):
1046 if rep.get(p).asString() !=
'ack':
1049 logging.info(
'Monitoring ' + rep.get(p).asString())
1054 logging.info(
'Connect ' + str(op[0]) +
' to ' + rep.get(p).asString())
1055 yarp.Network.connect(op[0], rep.get(p).asString())
1057 logging.info(
'Connect ' + rep.get(p).asString() +
' to ' + str(op[0]))
1058 yarp.Network.connect(rep.get(p).asString(), op[0])
1059 reply.addString(
'ack')
1060 reply.addString(str(interactionFunction[0]) +
" model loaded at " +
1061 interfacePortName +
" with call signs " + str(callSignList))
1063 reply.addString(
'nack')
1064 reply.addString(
'No interaction function found in ' + command.get(1).asString() +
1065 ' model path. Skipping model')
1067 reply.addString(
'nack')
1068 reply.addString(
'Parameters "driver" and "modelBaseName" not found in config.ini')
1070 reply.addString(
'nack')
1071 reply.addString(
"Failed to retrieve " + command.get(1).asString() +
" model. Model not trained")
1073 reply.addString(
'nack')
1074 reply.addString(command.get(1).asString() +
" model does not exist")
1077 def checkModel(self, reply, command, allCheck=False):
1078 """ Check availability and status of a model. 1081 Cross check available models, data folders, config files and driver availability for a specific model. 1084 reply : Yarp bottle for the reply from the function. 1085 command : Yarp bottle with the command and the model name to check. 1086 allCheck : Boolean to check all models if True and check a single model if False. 1089 Boolean indicating success or not. 1094 if command.size() != 2:
1095 repStr +=
"Model name required. e.g. check Actions" 1097 repStr += command.get(1).asString()+
" in training" 1099 repStr += command.get(1).asString()+
" is up-to-date" 1101 repStr += command.get(1).asString()+
" requires update" 1103 repStr += command.get(1).asString()+
" has no model" 1105 repStr += command.get(1).asString()+
" model not present" 1107 if any(e[0] == command.get(1).asString()
for e
in self.
rpcConnections):
1108 repStr +=
" and is loaded" 1110 repStr +=
" and is not loaded" 1112 reply.addString(
'ack')
1113 reply.addString(repStr)
1116 def train(self, reply, command):
1117 """ Logic for training a model. 1120 Checks that requested model is present and available for training. 1123 reply : Yarp bottle for the reply from the function. 1124 command : Yarp bottle with the command and the model name to train. 1127 Boolean indicating success or not. 1131 if command.size() != 2:
1132 reply.addString(
'nack')
1133 reply.addString(
"Model name required. e.g. train Actions")
1135 reply.addString(
'nack')
1136 reply.addString(command.get(1).asString() +
" is already up to date.")
1138 reply.addString(
'nack')
1139 reply.addString(command.get(1).asString() +
" is already being trained.")
1141 reply.addString(
'ack')
1142 reply.addString(
"Training " + command.get(1).asString() +
" model ...")
1143 modelToTrain = [s
for s
in self.
updateModels + self.
noModels if s[0] == command.get(1).asString()][0]
1145 logging.info(modelToTrain)
1148 reply.addString(
'nack')
1149 reply.addString(command.get(1).asString() +
" model not available to train")
1153 def optimise(self, reply, command):
1154 """ Logic for optimising a model. 1157 Checks that requested model is present and available for optimisation. 1160 reply : Yarp bottle for the reply from the function. 1161 command : Yarp bottle with the command and the model name to optimise. 1164 Boolean indicating success or not. 1168 if command.size() < 2:
1169 reply.addString(
'nack')
1170 reply.addString(
"Model name required. e.g. optimise Actions")
1172 reply.addString(
'nack')
1173 reply.addString(command.get(1).asString() +
" is already being trained.")
1175 reply.addString(
'nack')
1176 reply.addString(
"Train " + command.get(1).asString() +
" model before optimising")
1179 reply.addString(
'ack')
1180 reply.addString(
"Optimising " + command.get(1).asString() +
" model ...")
1183 logging.info(modelToTrain)
1184 self.
optimise_model(modelToTrain, modName=command.get(2).asString())
1186 reply.addString(
'nack')
1187 reply.addString(command.get(1).asString() +
" model not available to optimise")
1192 """ Deletes model from hard disk. 1195 reply : Yarp bottle for the reply from the function. 1196 command : Yarp bottle with the command and the model name to delete. 1199 Boolean indicating success or not. 1206 if k[0] == command.get(1).asString():
1209 if command.size() < 2:
1210 reply.addString(
'nack')
1211 reply.addString(
"Model name required. e.g. delete Actions")
1213 reply.addString(
'nack')
1214 reply.addString(
"Cannot delete model. Model in training")
1216 reply.addString(
'nack')
1217 reply.addString(
"Cannot delete model. Model currently loaded")
1222 if s[0] == command.get(1).asString()][0][4]
1224 for j
in modelToDelete.keys():
1225 if 'L' in modelToDelete[j].split(
'__')[-1]:
1226 modelToDelete[j] =
'__'.join(modelToDelete.split(
'__')[:-1])
1229 if command.get(2).asString() !=
'':
1230 modName = command.get(2).asString()
1231 if modName
in modelToDelete.keys():
1232 if modelToDelete[modName] !=
'':
1233 filesToDelete += glob.glob(join(self.
modelPath, modelToDelete[modName] +
'*'))
1235 for j
in modelToDelete.keys():
1236 if modelToDelete[j] !=
'':
1237 filesToDelete += glob.glob(join(self.
modelPath, modelToDelete[j] +
'*'))
1238 logging.info(filesToDelete)
1240 for i
in filesToDelete:
1246 if len(filesToDelete) > 0
and not failFlag:
1247 reply.addString(
'ack')
1248 reply.addString(str(command.get(1).asString()) +
" model deleted.")
1249 elif len(filesToDelete) == 0:
1250 reply.addString(
'nack')
1251 reply.addString(
'Model name with ' + command.get(2).asString() +
' not found')
1253 reply.addString(
'nack')
1254 reply.addString(
'Error when deleting file')
1259 reply.addString(
'nack')
1260 reply.addString(str(command.get(1).asString()) +
" model not present")
1264 """ Displays the model configuration file using a system call to gedit. 1267 reply : Yarp bottle for the reply from the function. 1268 command : Yarp bottle with the command and the model name to display. 1271 Boolean indicating success or not. 1274 if command.size() != 2:
1275 reply.addString(
'nack')
1276 reply.addString(
"Model name required. e.g. report Actions")
1281 if s[0] == command.get(1).asString()][0][0]
1283 logging.info(modelToCheck)
1285 modelConfFile = join(self.
dataPath, modelToCheck,
'config.ini')
1286 os.system(
"gedit " + modelConfFile)
1287 reply.addString(
'ack')
1288 reply.addString(modelToCheck)
1290 reply.addString(
'nack')
1294 """ Returns the chosen model 1297 samOptimiser creates multiple models with different suffixes. `best` indicates the best performing model. `exp` indicates the last trained model. `backup` indicates the model present before optimisation started. The priority of suffixes is `best`, `exp`, `backup`. 1300 reply : Yarp bottle for the reply from the function. 1301 command : Yarp bottle with the command and the model name to chose. 1304 Boolean indicating success or not. 1307 if command.size() < 2:
1308 reply.addString(
'nack')
1309 reply.addString(
"Model name required. e.g. dataDir Actions")
1314 if s[0] == command.get(1).asString()][0][4]
1316 modType = command.get(2).asString()
1319 if modType
in modelToCheck.keys():
1320 if modelToCheck[modType] !=
'':
1321 modToLoad = modelToCheck[modType]
1324 if modelToCheck[modType] !=
'':
1325 modToLoad = modelToCheck[modType]
1328 modToLoad = join(self.
modelPath, modToLoad) +
'.pickle' 1329 logging.info(modToLoad)
1330 reply.addString(
'ack')
1331 reply.addString(modToLoad)
1333 reply.addString(
'nack')
1334 reply.addString(
'Could not find model type ' + modType)
1336 reply.addString(
'nack')
1337 reply.addString(
'Could not find ' + command.get(1).asString())
1342 """ Returns the performance of the trained model. 1345 Returns the confusion matrix for a trained model or returns the confusion matrix together with a plot of the matrix. 1348 reply : Yarp bottle for the reply from the function. 1349 command : Yarp bottle with the command, the model name to report and a plot parameter to switch plot on or off. 1352 report <modelName> \n 1353 report <modelName> plot 1356 Boolean indicating success or not. 1360 if command.size() < 2:
1361 reply.addString(
'nack')
1362 reply.addString(
"Model name required. e.g. report Actions")
1367 if command.size() == 3
and command.get(2).asString() ==
'plot':
1371 if s[0] == command.get(1).asString()][0][4]
1373 for j
in modelToCheck.keys():
1374 if 'L' in modelToCheck[j].split(
'__')[-1]:
1375 modelToCheck[j] =
'__'.join(modelToCheck.split(
'__')[:-1])
1377 reply.addVocab(yarp.Vocab_encode(
"many"))
1379 for j
in modelToCheck.keys():
1380 if modelToCheck[j] !=
'':
1381 filesToCheck = glob.glob(join(self.
modelPath, modelToCheck[j] +
'*'))
1382 for i
in filesToCheck:
1384 modelPickle = pickle.load(open(i,
'rb'))
1385 reply.addString(
'ack')
1386 reply.addString(modelToCheck[j]+
":")
1388 perfLabels = modelPickle[
'overallPerformanceLabels']
1391 perfCM = modelPickle[
'overallPerformance']
1394 utils.plot_confusion_matrix(perfCM, perfLabels, title=modelToCheck[j])
1396 if perfLabels
is not None:
1397 reply.addString(str(perfLabels))
1398 reply.addString(str(perfCM))
1399 reply.addString(
"\t"+
" ")
1401 reply.addString(
'nack')
1402 reply.addString(str(command.get(1).asString()) +
" model not present")
1409 Launches trainSAMModel.py to train the specified model. 1412 mod : String with the model name to load. 1415 Boolean indicating success or not. 1418 logging.info(
"Training Models:")
1425 trainPath =
'trainSAMModel.py' 1428 logging.info(
'Training ' + mod[0] +
' ...')
1429 logging.info(
'Opening ' + trainPath)
1431 dPath = join(self.
dataPath, mod[0])
1434 modToTrain = mod[4][
'exp']
1438 if modToTrain !=
'':
1439 mPath = join(self.
modelPath, modToTrain) +
'.pickle' 1441 mPath = join(self.
modelPath, modToTrain)
1455 args =
' '.join([dPath, mPath, mod[1],
'update', mod[0], str(self.
windowed)])
1457 args =
' '.join([dPath, mPath, mod[1],
'new', mod[0], str(self.
windowed)])
1460 logging.info(
'args: ' + str(args))
1465 cmd = trainPath +
' ' + args
1467 command =
"bash -c \"" + cmd +
"; exec bash\"" 1469 command =
"bash -c \"" + cmd +
"\"" 1472 logging.info(
'cmd: ' + str(cmd))
1475 c = subprocess.Popen([self.
terminal,
'-e', command], shell=
False)
1478 c = subprocess.Popen([cmd], shell=
True)
1485 """ Optimise a model. 1488 Launches samOptimiser.py to optimise the specified model. 1491 mod : Model information. 1492 modName : Model name. 1495 Boolean indicating success or not. 1498 logging.info(
"Training Models:")
1505 trainPath =
'trainSAMModel.py' 1508 logging.info(
'Optimising ' + mod[0] +
' ...')
1510 dPath = join(self.
dataPath, mod[0])
1513 if modName !=
'' and modName
in mod[4].keys():
1514 if mod[4][modName] !=
'':
1515 modToUse = mod[4][modName]
1518 if mod[4][nm] !=
'':
1519 modToUse = mod[4][nm]
1522 mPath = join(self.
modelPath, modToUse) +
'.pickle' 1534 args =
' '.join([dPath, mPath, mod[1],
'new', mod[0],
'False',
'False',
'True'])
1537 logging.info(
'args: ' + str(args))
1539 cmd =
'samOptimiser.py ' + trainPath +
' ' + args
1541 command =
"bash -c \"" + cmd +
"; exec bash\"" 1543 command =
"bash -c \"" + cmd +
"\"" 1546 logging.info(
'cmd: ' + str(cmd))
1549 c = subprocess.Popen([self.
terminal,
'-e', command], shell=
False)
1551 c = subprocess.Popen([cmd], shell=
True)
1559 Module refresh rate. 1561 Returns : The period of the module in seconds. 1566 """ Check status of loaded models. 1569 Checks that ports for all loaded models are alive and working. If a loaded model is not working restart the model. 1584 logging.info(str(i) +
' terminated successfully')
1600 correctOperation = correctOp_check1
and correctOp_check2
1601 if not correctOperation
and self.
rpcConnections[j][-1] !=
'loading':
1610 logging.error(
'Restarting ' + str(self.
rpcConnections[j][0]) +
' model')
1614 cmd.addString(
"load")
1615 cmd.addString(currModelName)
1620 cmd.addString(
"close")
1624 logging.info(currModelName)
1638 logging.info(
'pinging portNames to ' + str(self.
rpcConnections[n][0]))
1641 cmd.addString(
"portNames")
1644 logging.info(
'ping received ' + str(rep.toString()))
1646 if rep.size() > 1
and rep.get(0).asString() ==
'ack':
1647 for p
in range(rep.size()):
1648 if rep.get(p).asString() !=
'ack':
1651 logging.info(
'Monitoring ' + str(rep.get(p).asString()))
1654 logging.info(
'ping ' + str(k))
1655 proc = subprocess.Popen([
'yarp',
'ping', k], stdout=subprocess.PIPE)
1656 output = proc.stdout.read()
1660 conStrings = output.split(
'\n')[1:]
1662 for g
in conStrings:
1663 if 'output conn' in g:
1665 elif 'input conn' in g:
1670 if 'from' in g
and dirConnect
is not None:
1671 parts = g.split(
' ')
1672 if dirConnect ==
'out':
1673 connList.append([parts[8], dirConnect])
1674 elif dirConnect ==
'in' and '<ping>' not in g:
1675 connList.append([parts[6], dirConnect])
1685 Check heartbeat of model. 1688 j : Yarp rpc port for loaded model to check. 1691 correctOp_check1 : Check that output count for the model rpc port is > 0. 1692 correctOp_check2 : Check that the model returns `ack` to a `hartbeat` request. 1695 correctOp_check1 =
True if j[1].getOutputCount() > 0
else False 1698 cmd.addString(
"heartbeat")
1699 j[1].write(cmd, rep)
1700 correctOp_check2 =
True if rep.get(0).asString() ==
'ack' else False 1702 return correctOp_check1, correctOp_check2
1706 Logic to execute every getPeriod() seconds. 1709 This function makes checks that all loaded modules are still alive and if OPC querying is enabled query OPC. 1711 Returns: Boolean indicating success of logic or not. 1725 """Callback function to record any errors that occur in the log files. 1728 Substitutes the standard python exception_hook with one that records the error into a log file. Can only work if interactionSAMModel.py is called from python and not ipython because ipython overrides this substitution. 1730 exc_type: Exception Type. 1731 exc_value: Exception Value. 1732 exc_traceback: Exception Traceback. 1737 logging.error(
"Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
1739 sys.excepthook = exception_hook
1741 if __name__ ==
'__main__':
1746 yrf = yarp.ResourceFinder()
1747 yrf.setVerbose(
True)
1748 yrf.setDefaultContext(
"samSupervisor")
1749 yrf.setDefaultConfigFile(
"default.ini")
1750 yrf.configure(sys.argv)
1752 samMod.runModule(yrf)
def train(self, reply, command)
Logic for training a model.
def reportModel(self, reply, command)
Returns the performance of the trained model.
def listModels(self, reply, command)
Returns lists of models for train or interaction categpories.
def interruptModule(self)
Module interrupt logic.
def train_model(self, mod)
Train a model.
def configModel(self, reply, command)
Displays the model configuration file using a system call to gedit.
def forwardCommand(self, command, reply)
Helper function to forward a call sign to the respective model with an enforced timeout of 10 seconds...
def configure(self, rf)
Configure interactionSAMModel Yarp module.
def checkAvailabilities(self, reply)
Check model availabilities.
def optimise(self, reply, command)
Logic for optimising a model.
Model management and supervisor.
def askOPC(self, reply)
Query the OPC for additional contextual data.
def dataDirModel(self, reply, command)
Returns the chosen model.
def checkModel(self, reply, command, allCheck=False)
Check availability and status of a model.
def checkOperation(self, j)
Check heartbeat of model.
def deleteModel(self, reply, command)
Deletes model from hard disk.
def close(self)
Close Yarp module.
def exception_hook(exc_type, exc_value, exc_traceback)
Callback function to record any errors that occur in the log files.
def updateModule(self)
Logic to execute every getPeriod() seconds.
def optimise_model(self, mod, modName)
Optimise a model.
def onlineModelCheck(self)
Check status of loaded models.
def closeModel(self, reply, command, external=False)
Close a loaded model.
def respond(self, command, reply)
Respond to external requests.
def loadModel(self, reply, command)
Load a trained model.
def getPeriod(self)
Module refresh rate.
def attentionModulation(self, reply, command)
Modulate attention of all models.