File size: 4,403 Bytes
aaec566
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import numpy as np
import torch
from typing import List, Union, Dict
from transformers import AutoTokenizer, AutoModel
from pathlib import Path
import json

class LocalEmbedder:
    def __init__(self, model_name: str, device: str = None, batch_size: int = 32):
        """
        Ініціалізація локальної моделі для ембедінгів
        
        Args:
            model_name: назва або шлях до моделі (з HuggingFace або локальна)
            device: пристрій для обчислень ('cuda', 'cpu' або None - автовибір)
            batch_size: розмір батчу для інференсу
        """
        self.model_name = model_name
        self.batch_size = batch_size
        
        # Визначення пристрою
        if device is None:
            self.device = 'cuda' if torch.cuda.is_available() else 'cpu'
        else:
            self.device = device
            
        # Завантаження моделі та токенізатора
        self.tokenizer = AutoTokenizer.from_pretrained(model_name)
        self.model = AutoModel.from_pretrained(model_name).to(self.device)
        self.model.eval()
        
        # Максимальна довжина послідовності
        self.max_length = self.tokenizer.model_max_length
        if self.max_length > 512:
            self.max_length = 512
            
    def _normalize_embeddings(self, embeddings: np.ndarray) -> np.ndarray:
        """
        L2-нормалізація ембедінгів
        
        Args:
            embeddings: матриця ембедінгів
            
        Returns:
            np.ndarray: нормалізована матриця ембедінгів
        """
        norms = np.linalg.norm(embeddings, axis=1, keepdims=True)
        return embeddings / norms
            
    def get_embeddings(self, texts: Union[str, List[str]]) -> np.ndarray:
        """
        Отримання ембедінгів для тексту або списку текстів
        
        Args:
            texts: текст або список текстів
            
        Returns:
            np.ndarray: матриця нормалізованих ембедінгів
        """
        if isinstance(texts, str):
            texts = [texts]
            
        all_embeddings = []
        
        with torch.no_grad():
            for i in range(0, len(texts), self.batch_size):
                batch_texts = texts[i:i + self.batch_size]
                
                # Токенізація
                encoded = self.tokenizer.batch_encode_plus(
                    batch_texts,
                    padding=True,
                    truncation=True,
                    max_length=self.max_length,
                    return_tensors='pt'
                )
                
                # Переміщуємо тензори на потрібний пристрій
                input_ids = encoded['input_ids'].to(self.device)
                attention_mask = encoded['attention_mask'].to(self.device)
                
                # Отримуємо ембедінги
                outputs = self.model(
                    input_ids=input_ids,
                    attention_mask=attention_mask
                )
                
                # Використовуємо [CLS] токен як ембедінг
                embeddings = outputs.last_hidden_state[:, 0, :]
                all_embeddings.append(embeddings.cpu().numpy())
                
        # Об'єднуємо всі батчі
        embeddings = np.vstack(all_embeddings)
        
        # Нормалізуємо ембедінги
        normalized_embeddings = self._normalize_embeddings(embeddings)
        
        return normalized_embeddings
    
    def get_model_info(self) -> Dict[str, any]:
        """
        Отримання інформації про модель
        
        Returns:
            Dict: інформація про модель
        """
        return {
            'model_name': self.model_name,
            'device': self.device,
            'embedding_size': self.model.config.hidden_size,
            'max_length': self.max_length,
            'batch_size': self.batch_size
        }