DOCS/GPT_docs/09_감정_임베딩_설계.md
happybell80 14ca47ed6e 로빙(RO-BEING) 프로젝트 상세 문서 20개 추가
- 비전 및 철학: 존재형 AI 에이전트 개념
- 윤리 원칙과 안전 기준
- 사용자 시나리오 및 유즈케이스
- 게임화 요소 (레벨업, 스탯, 스킬)
- 기술 아키텍처 (기억 시스템, 감정 모델, DB 설계)
- 멀티 에이전트 협업 구조
- DID 기반 신원 체계
- 장기 로드맵 (1년, 3년 비전)
2025-08-18 12:25:55 +09:00

14 KiB

감정 임베딩 설계와 벡터 공간 정의

감정 벡터 공간 아키텍처

다차원 감정 모델

import numpy as np
from dataclasses import dataclass

@dataclass
class EmotionSpace:
    """Russell의 Circumplex Model + Plutchik의 감정 바퀴 통합"""
    
    # 기본 차원 (3D)
    valence: float  # -1 (부정) to +1 (긍정)
    arousal: float  # 0 (차분) to 1 (흥분)
    dominance: float  # 0 (순종) to 1 (지배)
    
    # 확장 차원 (추가 5D)
    anticipation: float  # 0 to 1 (기대감)
    trust: float  # 0 to 1 (신뢰)
    surprise: float  # 0 to 1 (놀람)
    social_connection: float  # -1 (고립) to +1 (연결)
    certainty: float  # 0 (불확실) to 1 (확신)
    
    def to_vector(self):
        """8차원 감정 벡터 생성"""
        return np.array([
            self.valence, self.arousal, self.dominance,
            self.anticipation, self.trust, self.surprise,
            self.social_connection, self.certainty
        ])

기본 감정 임베딩

class BasicEmotionEmbeddings:
    """Ekman의 6가지 기본 감정 + 확장"""
    
    EMOTIONS = {
        'joy': {
            'vector': [0.9, 0.7, 0.7, 0.6, 0.8, 0.1, 0.8, 0.8],
            'color': '#FFD700',  # Gold
            'intensity_range': (0.3, 1.0)
        },
        'sadness': {
            'vector': [-0.8, 0.2, 0.2, 0.1, 0.3, 0.0, -0.3, 0.4],
            'color': '#4169E1',  # Royal Blue
            'intensity_range': (0.2, 0.9)
        },
        'anger': {
            'vector': [-0.7, 0.9, 0.8, 0.2, 0.1, 0.2, -0.2, 0.7],
            'color': '#DC143C',  # Crimson
            'intensity_range': (0.3, 1.0)
        },
        'fear': {
            'vector': [-0.8, 0.8, 0.1, 0.7, 0.1, 0.7, -0.1, 0.1],
            'color': '#8B008B',  # Dark Magenta
            'intensity_range': (0.4, 1.0)
        },
        'disgust': {
            'vector': [-0.9, 0.5, 0.6, 0.0, 0.0, 0.3, -0.4, 0.8],
            'color': '#556B2F',  # Dark Olive Green
            'intensity_range': (0.3, 0.9)
        },
        'surprise': {
            'vector': [0.1, 0.8, 0.3, 0.1, 0.4, 1.0, 0.2, 0.0],
            'color': '#FF69B4',  # Hot Pink
            'intensity_range': (0.5, 1.0)
        },
        'anticipation': {
            'vector': [0.3, 0.6, 0.5, 1.0, 0.5, 0.4, 0.4, 0.3],
            'color': '#FFA500',  # Orange
            'intensity_range': (0.2, 0.8)
        },
        'trust': {
            'vector': [0.7, 0.3, 0.4, 0.3, 1.0, 0.0, 0.9, 0.9],
            'color': '#32CD32',  # Lime Green
            'intensity_range': (0.1, 1.0)
        }
    }
    
    def get_embedding(self, emotion_name, intensity=0.5):
        """감정 이름과 강도로 임베딩 벡터 생성"""
        if emotion_name not in self.EMOTIONS:
            return None
            
        base_vector = np.array(self.EMOTIONS[emotion_name]['vector'])
        min_int, max_int = self.EMOTIONS[emotion_name]['intensity_range']
        
        # 강도 조정
        adjusted_intensity = min_int + (max_int - min_int) * intensity
        return base_vector * adjusted_intensity

복합 감정 모델링

감정 블렌딩 알고리즘

class EmotionBlending:
    def __init__(self):
        self.basic_emotions = BasicEmotionEmbeddings()
        
    def blend_emotions(self, emotion_mix):
        """
        여러 감정을 혼합하여 복합 감정 생성
        
        emotion_mix: {'joy': 0.6, 'surprise': 0.4}
        """
        blended_vector = np.zeros(8)
        total_weight = sum(emotion_mix.values())
        
        for emotion, weight in emotion_mix.items():
            emotion_vector = self.basic_emotions.get_embedding(emotion, weight)
            if emotion_vector is not None:
                blended_vector += emotion_vector * (weight / total_weight)
        
        # 정규화
        return self.normalize_vector(blended_vector)
    
    def create_complex_emotions(self):
        """복합 감정 정의"""
        complex_emotions = {
            'nostalgia': self.blend_emotions({'joy': 0.4, 'sadness': 0.6}),
            'bittersweetness': self.blend_emotions({'joy': 0.5, 'sadness': 0.5}),
            'anxiety': self.blend_emotions({'fear': 0.7, 'anticipation': 0.3}),
            'contempt': self.blend_emotions({'disgust': 0.6, 'anger': 0.4}),
            'awe': self.blend_emotions({'surprise': 0.5, 'fear': 0.2, 'joy': 0.3}),
            'guilt': self.blend_emotions({'sadness': 0.5, 'fear': 0.3, 'disgust': 0.2}),
            'pride': self.blend_emotions({'joy': 0.7, 'dominance': 0.3}),
            'shame': self.blend_emotions({'sadness': 0.4, 'fear': 0.3, 'disgust': 0.3})
        }
        return complex_emotions
    
    def normalize_vector(self, vector):
        """벡터 정규화"""
        norm = np.linalg.norm(vector)
        if norm == 0:
            return vector
        return vector / norm

시간적 감정 역학

감정 전이 모델

class EmotionDynamics:
    def __init__(self):
        self.emotion_history = []
        self.transition_matrix = self.build_transition_matrix()
        
    def build_transition_matrix(self):
        """감정 간 전이 확률 매트릭스"""
        # 8x8 매트릭스 (8개 기본 감정)
        # 행: 현재 감정, 열: 다음 감정
        transitions = np.array([
            # joy → [joy, sad, anger, fear, disgust, surprise, anticipation, trust]
            [0.6, 0.1, 0.05, 0.05, 0.02, 0.08, 0.1, 0.1],
            # sadness → ...
            [0.15, 0.5, 0.1, 0.1, 0.05, 0.02, 0.03, 0.05],
            # ... 나머지 감정들
        ])
        return transitions
    
    def predict_next_emotion(self, current_emotion, context_modifier=None):
        """현재 감정에서 다음 감정 예측"""
        current_idx = self.emotion_to_index(current_emotion)
        transition_probs = self.transition_matrix[current_idx]
        
        if context_modifier:
            # 컨텍스트에 따른 확률 조정
            transition_probs = self.apply_context(transition_probs, context_modifier)
        
        next_emotion_idx = np.random.choice(8, p=transition_probs)
        return self.index_to_emotion(next_emotion_idx)
    
    def emotion_trajectory(self, initial_emotion, steps=10):
        """감정 변화 궤적 시뮬레이션"""
        trajectory = [initial_emotion]
        current = initial_emotion
        
        for _ in range(steps):
            current = self.predict_next_emotion(current)
            trajectory.append(current)
            
        return trajectory

감정 반감기와 지속성

class EmotionPersistence:
    def __init__(self):
        # 각 감정의 반감기 (초 단위)
        self.half_lives = {
            'surprise': 30,      # 빠르게 사라짐
            'anger': 300,        # 5분
            'fear': 600,         # 10분
            'joy': 1800,         # 30분
            'sadness': 3600,     # 1시간
            'disgust': 1200,     # 20분
            'anticipation': 900, # 15분
            'trust': 7200        # 2시간
        }
    
    def decay_function(self, emotion, time_elapsed):
        """지수 감쇠 함수"""
        half_life = self.half_lives.get(emotion, 1800)
        decay_rate = np.log(2) / half_life
        
        intensity = np.exp(-decay_rate * time_elapsed)
        return intensity
    
    def emotional_residue(self, past_emotions, current_time):
        """과거 감정의 현재 영향"""
        residue = np.zeros(8)
        
        for emotion_event in past_emotions:
            time_diff = current_time - emotion_event['timestamp']
            intensity = self.decay_function(
                emotion_event['emotion'],
                time_diff
            )
            
            if intensity > 0.01:  # 1% 이상만 고려
                emotion_vector = emotion_event['vector']
                residue += emotion_vector * intensity
        
        return residue

감정-인지 상호작용

감정이 의사결정에 미치는 영향

class EmotionCognitionInterface:
    def __init__(self):
        self.emotion_weights = {
            'risk_assessment': {
                'fear': -0.8,      # 위험 회피
                'anger': 0.3,      # 위험 감수
                'joy': 0.2,        # 낙관적 평가
                'anticipation': 0.4 # 기회 추구
            },
            'creativity': {
                'joy': 0.7,
                'surprise': 0.6,
                'sadness': 0.3,    # 성찰적 창의성
                'anger': -0.2
            },
            'attention_focus': {
                'fear': 0.9,       # 높은 집중
                'anger': 0.7,
                'joy': -0.1,       # 분산된 주의
                'sadness': 0.4     # 세부사항 집중
            }
        }
    
    def modulate_decision(self, base_decision, emotional_state):
        """감정 상태에 따른 의사결정 조정"""
        modulated = base_decision.copy()
        
        for cognitive_function, emotion_effects in self.emotion_weights.items():
            for emotion, weight in emotion_effects.items():
                emotion_intensity = emotional_state.get(emotion, 0)
                modulated[cognitive_function] *= (1 + weight * emotion_intensity)
        
        return modulated
    
    def emotional_bias_correction(self, decision, emotion_intensity):
        """감정 편향 보정"""
        if emotion_intensity > 0.7:
            # 강한 감정 상태에서는 합리성 체크 강화
            return self.apply_rationality_filter(decision)
        return decision

감정 임베딩 학습

자기지도 학습 모델

class EmotionEmbeddingLearning:
    def __init__(self, embedding_dim=128):
        self.embedding_dim = embedding_dim
        self.emotion_encoder = self.build_encoder()
        
    def build_encoder(self):
        """감정 인코더 네트워크"""
        import tensorflow as tf
        
        model = tf.keras.Sequential([
            tf.keras.layers.Input(shape=(8,)),  # 8D 기본 감정 벡터
            tf.keras.layers.Dense(64, activation='relu'),
            tf.keras.layers.Dense(128, activation='relu'),
            tf.keras.layers.Dense(self.embedding_dim, activation='tanh'),
            tf.keras.layers.Lambda(lambda x: tf.nn.l2_normalize(x, axis=1))
        ])
        
        return model
    
    def contrastive_learning(self, anchor, positive, negative):
        """대조 학습으로 감정 임베딩 개선"""
        anchor_emb = self.emotion_encoder(anchor)
        positive_emb = self.emotion_encoder(positive)
        negative_emb = self.emotion_encoder(negative)
        
        # Triplet loss
        pos_dist = tf.reduce_sum(tf.square(anchor_emb - positive_emb), axis=1)
        neg_dist = tf.reduce_sum(tf.square(anchor_emb - negative_emb), axis=1)
        
        loss = tf.maximum(pos_dist - neg_dist + 0.2, 0)
        return tf.reduce_mean(loss)

감정 시각화

감정 공간 매핑

class EmotionVisualization:
    def __init__(self):
        self.color_map = self.create_color_map()
        
    def create_color_map(self):
        """감정을 색상으로 매핑"""
        return {
            'valence': {
                'positive': '#FFD700',  # 황금색
                'negative': '#4B0082'   # 인디고
            },
            'arousal': {
                'high': '#FF0000',      # 빨강
                'low': '#0000FF'        # 파랑
            }
        }
    
    def emotion_to_color(self, emotion_vector):
        """감정 벡터를 RGB 색상으로 변환"""
        valence = emotion_vector[0]  # -1 to 1
        arousal = emotion_vector[1]  # 0 to 1
        dominance = emotion_vector[2]  # 0 to 1
        
        # RGB 매핑
        r = int(128 + valence * 127)  # Valence → Red
        g = int(arousal * 255)        # Arousal → Green  
        b = int(dominance * 255)      # Dominance → Blue
        
        return f'#{r:02x}{g:02x}{b:02x}'
    
    def plot_emotion_trajectory(self, emotion_sequence):
        """감정 변화를 2D/3D 공간에 플로팅"""
        import matplotlib.pyplot as plt
        from mpl_toolkits.mplot3d import Axes3D
        
        fig = plt.figure(figsize=(12, 5))
        
        # 2D plot (Valence-Arousal)
        ax1 = fig.add_subplot(121)
        valences = [e[0] for e in emotion_sequence]
        arousals = [e[1] for e in emotion_sequence]
        
        ax1.plot(valences, arousals, 'o-', markersize=8)
        ax1.set_xlabel('Valence')
        ax1.set_ylabel('Arousal')
        ax1.set_title('Emotion Trajectory (2D)')
        ax1.grid(True, alpha=0.3)
        
        # 3D plot (Valence-Arousal-Dominance)
        ax2 = fig.add_subplot(122, projection='3d')
        dominances = [e[2] for e in emotion_sequence]
        
        ax2.plot(valences, arousals, dominances, 'o-', markersize=8)
        ax2.set_xlabel('Valence')
        ax2.set_ylabel('Arousal')
        ax2.set_zlabel('Dominance')
        ax2.set_title('Emotion Trajectory (3D)')
        
        plt.tight_layout()
        return fig

감정 메트릭

감정 다양성과 안정성 측정

class EmotionMetrics:
    def emotional_entropy(self, emotion_distribution):
        """감정 분포의 엔트로피 (다양성 측정)"""
        probs = np.array(list(emotion_distribution.values()))
        probs = probs / probs.sum()
        
        entropy = -np.sum(probs * np.log(probs + 1e-10))
        return entropy
    
    def emotional_stability(self, emotion_history):
        """감정 안정성 지수"""
        if len(emotion_history) < 2:
            return 1.0
        
        changes = []
        for i in range(1, len(emotion_history)):
            prev = emotion_history[i-1]
            curr = emotion_history[i]
            distance = np.linalg.norm(prev - curr)
            changes.append(distance)
        
        # 변화량의 표준편차 (낮을수록 안정적)
        stability = 1 / (1 + np.std(changes))
        return stability
    
    def emotional_valence_bias(self, emotion_history):
        """긍정/부정 편향 측정"""
        valences = [e[0] for e in emotion_history]
        mean_valence = np.mean(valences)
        
        if mean_valence > 0.2:
            return 'positive_bias', mean_valence
        elif mean_valence < -0.2:
            return 'negative_bias', mean_valence
        else:
            return 'neutral', mean_valence