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

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-%
quick_test: $(addprefix test-,$(PYMAIN))
dev-%:
@docker start $(NAME)-dev || (\
@docker start $(NAME)-dev$* || (\
$(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)
......
......@@ -17,7 +17,7 @@ import copy
import fnmatch
import inspect
import sys
import imp
import importlib
import logging
import traceback
import yaml
......@@ -181,7 +181,7 @@ class Senpy(object):
newentries = []
for i in resp.entries:
if output == "full":
newemotions = copy.copy(i.emotions)
newemotions = copy.deepcopy(i.emotions)
else:
newemotions = []
for j in i.emotions:
......@@ -303,6 +303,13 @@ class Senpy(object):
logger.info('Installing requirements: ' + str(requirements))
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
def _load_plugin_from_info(cls, info, root):
if not cls.validate_info(info):
......@@ -310,11 +317,10 @@ class Senpy(object):
return None, None
module = info["module"]
name = info["name"]
sys.path.append(root)
(fp, pathname, desc) = imp.find_module(module, [root, ])
cls._install_deps(info)
tmp = imp.load_module(module, fp, pathname, desc)
sys.path.remove(root)
tmp = cls._load_module(module, root)
candidate = None
for _, obj in inspect.getmembers(tmp):
if inspect.isclass(obj) and inspect.getmodule(obj) == tmp:
......
......@@ -7,7 +7,7 @@ import pickle
import logging
import tempfile
import copy
from . import models
from .. import models
logger = logging.getLogger(__name__)
......
......@@ -4,55 +4,49 @@ from senpy.models import EmotionSet, Emotion, Error
import logging
logger = logging.getLogger(__name__)
import math
class CentroidConversion(EmotionConversionPlugin):
class WNA2VAD(EmotionConversionPlugin):
def _ekman_to_vad(self, ekmanSet):
def _forward_conversion(self, original):
"""Sum the VAD value of all categories found."""
valence = 0
arousal = 0
dominance = 0
for e in ekmanSet.onyx__hasEmotion:
res = Emotion()
for e in original.onyx__hasEmotion:
category = e.onyx__hasEmotionCategory
centroid = self.centroids[category]
valence += centroid['V']
arousal += centroid['A']
dominance += centroid['D']
e = Emotion({'emoml:valence': valence,
'emoml:arousal': arousal,
'emoml:potency': dominance})
return e
def _vad_to_ekman(self, VADEmotion):
if category in self.centroids:
for dim, value in self.centroids[category].iteritems():
try:
res[dim] += value
except Exception:
res[dim] = value
return res
def _backwards_conversion(self, original):
"""Find the closest category"""
V = VADEmotion['emoml:valence']
A = VADEmotion['emoml:arousal']
D = VADEmotion['emoml:potency']
dimensions = list(self.centroids.values())[0]
def distance(e1, e2):
return sum((e1[k] - e2.get(self.aliases[k], 0)) for k in dimensions)
emotion = ''
value = 10000000000000000000000.0
mindistance = 10000000000000000000000.0
for state in self.centroids:
valence = V - self.centroids[state]['V']
arousal = A - self.centroids[state]['A']
dominance = D - self.centroids[state]['D']
new_value = math.sqrt((valence**2) +
(arousal**2) +
(dominance**2))
if new_value < value:
value = new_value
d = distance(self.centroids[state], original)
if d < mindistance:
mindistance = d
emotion = state
result = Emotion(onyx__hasEmotionCategory=emotion)
return result
def convert(self, emotionSet, fromModel, toModel, params):
cf, ct = self.centroids_direction
logger.debug('{}\n{}\n{}\n{}'.format(emotionSet, fromModel, toModel, params))
e = EmotionSet()
if fromModel == 'emoml:big6':
e.onyx__hasEmotion.append(self._ekman_to_vad(emotionSet))
elif fromModel == 'emoml:fsre-dimensions':
if fromModel == cf:
e.onyx__hasEmotion.append(self._forward_conversion(emotionSet))
elif fromModel == ct:
for i in emotionSet.onyx__hasEmotion:
e.onyx__hasEmotion.append(self._vad_to_ekman(i))
e.onyx__hasEmotion.append(self._backwards_conversion(i))
else:
raise Error('EMOTION MODEL NOT KNOWN')
yield e
---
name: Ekman2VAD
module: ekman2vad
module: senpy.plugins.conversion.centroids
description: Plugin to convert emotion sets from Ekman to VAD
version: 0.1
onyx:doesConversion:
......@@ -29,6 +29,9 @@ centroids:
A: 5.21
D: 2.82
V: 2.21
centroids_direction:
- emoml:big6
- emoml:fsre-dimensions
aliases:
A: emoml:arousal
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