Commit d8b59d06 authored by J. Fernando Sánchez's avatar J. Fernando Sánchez
Browse files

Converted Ekman2VAD to centroids

* Changed the way modules are imported -> we can now use dotted
  notation (e.g. senpy.plugins.conversion.centroids)
* Refactored ekman2vad's plugin -> generic centroids
* Added some basic tests
parent 453b9f32
...@@ -41,12 +41,12 @@ build-%: version Dockerfile-% ...@@ -41,12 +41,12 @@ build-%: version Dockerfile-%
quick_test: $(addprefix test-,$(PYMAIN)) quick_test: $(addprefix test-,$(PYMAIN))
dev-%: dev-%:
@docker start $(NAME)-dev || (\ @docker start $(NAME)-dev$* || (\
$(MAKE) build-$*; \ $(MAKE) build-$*; \
docker run -d -w /usr/src/app/ -v $$PWD:/usr/src/app --entrypoint=/bin/bash -p 5000:5000 -ti --name $(NAME)-dev '$(IMAGEWTAG)-python$*'; \ docker run -d -w /usr/src/app/ -v $$PWD:/usr/src/app --entrypoint=/bin/bash -ti --name $(NAME)-dev$* '$(IMAGEWTAG)-python$*'; \
)\ )\
docker exec -ti $(NAME)-dev bash docker exec -ti $(NAME)-dev$* bash
dev: dev-$(PYMAIN) dev: dev-$(PYMAIN)
......
...@@ -17,7 +17,7 @@ import copy ...@@ -17,7 +17,7 @@ import copy
import fnmatch import fnmatch
import inspect import inspect
import sys import sys
import imp import importlib
import logging import logging
import traceback import traceback
import yaml import yaml
...@@ -181,7 +181,7 @@ class Senpy(object): ...@@ -181,7 +181,7 @@ class Senpy(object):
newentries = [] newentries = []
for i in resp.entries: for i in resp.entries:
if output == "full": if output == "full":
newemotions = copy.copy(i.emotions) newemotions = copy.deepcopy(i.emotions)
else: else:
newemotions = [] newemotions = []
for j in i.emotions: for j in i.emotions:
...@@ -303,6 +303,13 @@ class Senpy(object): ...@@ -303,6 +303,13 @@ class Senpy(object):
logger.info('Installing requirements: ' + str(requirements)) logger.info('Installing requirements: ' + str(requirements))
pip.main(pip_args) pip.main(pip_args)
@classmethod
def _load_module(cls, name, root):
sys.path.append(root)
tmp = importlib.import_module(name)
sys.path.remove(root)
return tmp
@classmethod @classmethod
def _load_plugin_from_info(cls, info, root): def _load_plugin_from_info(cls, info, root):
if not cls.validate_info(info): if not cls.validate_info(info):
...@@ -310,11 +317,10 @@ class Senpy(object): ...@@ -310,11 +317,10 @@ class Senpy(object):
return None, None return None, None
module = info["module"] module = info["module"]
name = info["name"] name = info["name"]
sys.path.append(root)
(fp, pathname, desc) = imp.find_module(module, [root, ])
cls._install_deps(info) cls._install_deps(info)
tmp = imp.load_module(module, fp, pathname, desc) tmp = cls._load_module(module, root)
sys.path.remove(root)
candidate = None candidate = None
for _, obj in inspect.getmembers(tmp): for _, obj in inspect.getmembers(tmp):
if inspect.isclass(obj) and inspect.getmodule(obj) == tmp: if inspect.isclass(obj) and inspect.getmodule(obj) == tmp:
......
...@@ -7,7 +7,7 @@ import pickle ...@@ -7,7 +7,7 @@ import pickle
import logging import logging
import tempfile import tempfile
import copy import copy
from . import models from .. import models
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
......
...@@ -4,55 +4,49 @@ from senpy.models import EmotionSet, Emotion, Error ...@@ -4,55 +4,49 @@ from senpy.models import EmotionSet, Emotion, Error
import logging import logging
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
import math
class CentroidConversion(EmotionConversionPlugin):
class WNA2VAD(EmotionConversionPlugin): def _forward_conversion(self, original):
def _ekman_to_vad(self, ekmanSet):
"""Sum the VAD value of all categories found.""" """Sum the VAD value of all categories found."""
valence = 0 res = Emotion()
arousal = 0 for e in original.onyx__hasEmotion:
dominance = 0
for e in ekmanSet.onyx__hasEmotion:
category = e.onyx__hasEmotionCategory category = e.onyx__hasEmotionCategory
centroid = self.centroids[category] if category in self.centroids:
valence += centroid['V'] for dim, value in self.centroids[category].iteritems():
arousal += centroid['A'] try:
dominance += centroid['D'] res[dim] += value
e = Emotion({'emoml:valence': valence, except Exception:
'emoml:arousal': arousal, res[dim] = value
'emoml:potency': dominance}) return res
return e
def _backwards_conversion(self, original):
def _vad_to_ekman(self, VADEmotion):
"""Find the closest category""" """Find the closest category"""
V = VADEmotion['emoml:valence'] dimensions = list(self.centroids.values())[0]
A = VADEmotion['emoml:arousal']
D = VADEmotion['emoml:potency'] def distance(e1, e2):
return sum((e1[k] - e2.get(self.aliases[k], 0)) for k in dimensions)
emotion = '' emotion = ''
value = 10000000000000000000000.0 mindistance = 10000000000000000000000.0
for state in self.centroids: for state in self.centroids:
valence = V - self.centroids[state]['V'] d = distance(self.centroids[state], original)
arousal = A - self.centroids[state]['A'] if d < mindistance:
dominance = D - self.centroids[state]['D'] mindistance = d
new_value = math.sqrt((valence**2) +
(arousal**2) +
(dominance**2))
if new_value < value:
value = new_value
emotion = state emotion = state
result = Emotion(onyx__hasEmotionCategory=emotion) result = Emotion(onyx__hasEmotionCategory=emotion)
return result return result
def convert(self, emotionSet, fromModel, toModel, params): def convert(self, emotionSet, fromModel, toModel, params):
cf, ct = self.centroids_direction
logger.debug('{}\n{}\n{}\n{}'.format(emotionSet, fromModel, toModel, params)) logger.debug('{}\n{}\n{}\n{}'.format(emotionSet, fromModel, toModel, params))
e = EmotionSet() e = EmotionSet()
if fromModel == 'emoml:big6': if fromModel == cf:
e.onyx__hasEmotion.append(self._ekman_to_vad(emotionSet)) e.onyx__hasEmotion.append(self._forward_conversion(emotionSet))
elif fromModel == 'emoml:fsre-dimensions': elif fromModel == ct:
for i in emotionSet.onyx__hasEmotion: for i in emotionSet.onyx__hasEmotion:
e.onyx__hasEmotion.append(self._vad_to_ekman(i)) e.onyx__hasEmotion.append(self._backwards_conversion(i))
else: else:
raise Error('EMOTION MODEL NOT KNOWN') raise Error('EMOTION MODEL NOT KNOWN')
yield e yield e
--- ---
name: Ekman2VAD name: Ekman2VAD
module: ekman2vad module: senpy.plugins.conversion.centroids
description: Plugin to convert emotion sets from Ekman to VAD description: Plugin to convert emotion sets from Ekman to VAD
version: 0.1 version: 0.1
onyx:doesConversion: onyx:doesConversion:
...@@ -29,6 +29,9 @@ centroids: ...@@ -29,6 +29,9 @@ centroids:
A: 5.21 A: 5.21
D: 2.82 D: 2.82
V: 2.21 V: 2.21
centroids_direction:
- emoml:big6
- emoml:fsre-dimensions
aliases: aliases:
A: emoml:arousal A: emoml:arousal
V: emoml:valence V: emoml:valence
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment