File size: 5,839 Bytes
3462329
 
 
 
 
 
15012bd
3462329
15012bd
bbb5cc7
ecffe29
3462329
00ef496
ecffe29
 
 
 
 
 
bbb5cc7
3462329
 
50f33da
 
 
 
 
 
 
 
 
 
 
 
 
15012bd
50f33da
3462329
 
 
 
 
66525d8
 
69c39e7
15012bd
3462329
15012bd
3462329
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15012bd
3462329
 
 
15012bd
 
3462329
 
 
 
 
 
 
15012bd
 
ecffe29
 
3462329
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69c39e7
 
15012bd
3462329
 
d0f981b
 
c25c4e9
 
d0f981b
c25c4e9
d0f981b
f27384b
 
cb4f957
 
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import torch
import torch.nn.functional as F
import gradio as gr
from PIL import Image
import pickle
import json
from huggingface_hub import hf_hub_download

from model import image_captioning_model
from tokenizer import CaptionTokenizer  # Важно!

# Загрузка файлов
repo_id = "Pumponchik/ImageCaption"
repo_type = "space"
model_path = hf_hub_download(repo_id=repo_id, filename="pytorch_model.bin", repo_type=repo_type)
config_path = hf_hub_download(repo_id=repo_id, filename="config.json", repo_type=repo_type)
tokenizer_path = hf_hub_download(repo_id=repo_id, filename="tokenizer.pkl", repo_type=repo_type)
transform_path = hf_hub_download(repo_id=repo_id, filename="image_transforms.pkl", repo_type=repo_type)


# Загрузка конфигурации
with open(config_path, "r") as f:
    full_config = json.load(f)

# Фильтрация параметров для модели
model_params = {
    "vocab_size": full_config["vocab_size"],
    "embedding_dim": full_config["embedding_dim"],
    "hidden_size": full_config["hidden_size"],
    "num_layers": full_config["num_layers"]
}

# Инициализация модели
model = image_captioning_model(**model_params)

# Загрузка весов модели
model.load_state_dict(torch.load(model_path, map_location="cpu"), strict=False)

device = "cuda" if torch.cuda.is_available() else "cpu"
model.to(device)
model.eval()

tokenizer = CaptionTokenizer.load(tokenizer_path)


# Загрузка трансформаций
with open(transform_path, "rb") as f:
    transform = pickle.load(f)

def wrap_text(text, max_width):
    words = text.split(" ")
    result = [[words[0]]]
    for word in words[1:]:
        if len(" ".join(result[-1])) + len(word) + 1 > max_width:
            result[-1] = " ".join(result[-1])
            result.append([])
        result[-1].append(word)
    result[-1] = " ".join(result[-1])
    return "\n".join(result)

def generate(model, image, tokenizer, max_seq_len=20, top_p=None, top_k=1):
    assert top_p is None or top_k is None, "Не используйте одновременно top_p и top_k"

    model.eval()
    device = next(model.parameters()).device
    image = transform(image).to(device).unsqueeze(0)
    batch_size = image.size(0)

    with torch.no_grad():
        img_emb = model.img_fe(image)
        h_0 = model.img_to_hidden(img_emb).unsqueeze(0).repeat(model.text_fe.num_layers, 1, 1)
        c_0 = h_0.clone()

        input_token = torch.full((batch_size,), tokenizer.tok_to_ind['<BOS>'], dtype=torch.long, device=device)
        result_tokens = [[] for _ in range(batch_size)]
        mask = torch.ones(batch_size, dtype=torch.bool, device=device)

        for _ in range(max_seq_len):
            input_emb = model.text_fe.embedding(input_token).unsqueeze(1)
            output, (h_0, c_0) = model.text_fe.rnn(input_emb, (h_0, c_0))
            logits = model.fc_out(output.squeeze(1))
            probs = F.softmax(logits, dim=-1)

            next_tokens = torch.zeros(batch_size, dtype=torch.long, device=device)
            for i in range(batch_size):
                if not mask[i]:
                    continue
                prob = probs[i]
                if top_k is not None:
                    sorted_probs, sorted_indices = torch.sort(prob, descending=True)
                    sorted_probs = sorted_probs[:top_k]
                    sorted_indices = sorted_indices[:top_k]
                    sorted_probs = sorted_probs / sorted_probs.sum()
                    next_token_idx = torch.multinomial(sorted_probs, 1)
                    next_tokens[i] = sorted_indices[next_token_idx]
                elif top_p is not None:
                    sorted_probs, sorted_indices = torch.sort(prob, descending=True)
                    cumulative_probs = torch.cumsum(sorted_probs, dim=0)
                    mask_p = cumulative_probs <= top_p
                    sorted_probs = sorted_probs[mask_p]
                    sorted_indices = sorted_indices[mask_p]
                    sorted_probs = sorted_probs / sorted_probs.sum()
                    next_token_idx = torch.multinomial(sorted_probs, 1)
                    next_tokens[i] = sorted_indices[next_token_idx]
                else:
                    next_tokens[i] = torch.multinomial(prob, 1)

                token_id = next_tokens[i].item()
                result_tokens[i].append(token_id)
                if token_id == tokenizer.tok_to_ind['<EOS>']:
                    mask[i] = False

            input_token = next_tokens
            if not mask.any():
                break

        result_text = []
        for tokens in result_tokens:
            caption = " ".join([tokenizer.ind_to_tok.get(t, "<UNK>") for t in tokens 
                               if t not in [tokenizer.tok_to_ind.get("<BOS>", -1), 
                                           tokenizer.tok_to_ind.get("<EOS>", -1), 
                                           tokenizer.tok_to_ind.get("<PAD>", -1)]])
            result_text.append(caption)

    return result_text[0] if batch_size == 1 else result_text

def generate_caption(image):
    image = image.convert("RGB")
    max_seq_len = full_config.get("max_len", 20)
    caption = generate(model, image, tokenizer, max_seq_len=max_seq_len, top_k=5)
    caption = wrap_text(caption, 43)
    return caption

iface = gr.Interface(
    fn=generate_caption,
    inputs=gr.Image(type="pil", label="Загрузите изображение"),
    outputs=gr.Textbox(label="Сгенерированное описание"),
    title="Генерация описаний изображений",
    description="Загрузите изображение, и модель создаст текстовое описание."
)
iface.launch(
    server_name="0.0.0.0",
    server_port=7860,
)