klasser commited on
Commit
f1ba501
·
1 Parent(s): 0b0420a

Upload 15 files

Browse files
app.py ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import torch
3
+ import transformers
4
+ from trl import AutoModelForCausalLMWithValueHead
5
+
6
+ # Настройки страницы
7
+ st.set_page_config(page_title="RLHF: IMDB Movie Reviews", layout="wide")
8
+ st.title("🎬 Генерация отзывов на фильмы с помощью RLHF")
9
+ st.markdown("""
10
+ Это приложение сравнивает два варианта модели:
11
+ - **Original GPT-2**: базовая модель, обученная на отзывах IMDB.
12
+ - **RLHF Model (PPO)**: та же модель, но дообученная с помощью RLHF писать **только позитивные** отзывы.
13
+ """)
14
+
15
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
16
+
17
+ # ============================================================
18
+ # ЗАГРУЗКА МОДЕЛЕЙ (кешируем, чтобы не грузить при каждом нажатии)
19
+ # ============================================================
20
+ @st.cache_resource
21
+ def load_models():
22
+ with st.spinner("Загрузка моделей в память... Пожалуйста, подождите (это делается 1 раз)."):
23
+ # 1. Загрузка Reward Model
24
+ reward_path = "reward_model_trained"
25
+ reward_tokenizer = transformers.AutoTokenizer.from_pretrained(reward_path)
26
+ reward_model = transformers.AutoModelForSequenceClassification.from_pretrained(reward_path).to(DEVICE).eval()
27
+
28
+ # 2. Загрузка Original Model (Базовая до RLHF)
29
+ orig_model_name = "lvwerra/gpt2-imdb"
30
+ orig_tokenizer = transformers.AutoTokenizer.from_pretrained(orig_model_name)
31
+ if orig_tokenizer.pad_token is None:
32
+ orig_tokenizer.pad_token = orig_tokenizer.eos_token
33
+
34
+ orig_model = transformers.AutoModelForCausalLM.from_pretrained(orig_model_name).to(DEVICE).eval()
35
+
36
+ # 3. Загрузка RLHF Model (Обученная через PPO)
37
+ ppo_path = "ppo_model_trained"
38
+ # Для генерации нам нужен только CausalLM, но чтобы загрузить веса корректно, используем ValueHead класс
39
+ rlhf_model_full = AutoModelForCausalLMWithValueHead.from_pretrained(ppo_path).to(DEVICE).eval()
40
+ rlhf_model = rlhf_model_full.pretrained_model # вытаскиваем саму языковую модель
41
+
42
+ return reward_model, reward_tokenizer, orig_model, orig_tokenizer, rlhf_model
43
+
44
+ try:
45
+ reward_model, reward_tokenizer, orig_model, orig_tokenizer, rlhf_model = load_models()
46
+ except Exception as e:
47
+ st.error(f"Ошибка загрузки моделей! Убедитесь, что папки `reward_model_trained` и `ppo_model_trained` находятся рядом с app.py.\nДетали: {e}")
48
+ st.stop()
49
+
50
+ # ============================================================
51
+ # ФУНКЦИИ ГЕНЕРАЦИИ И ОЦЕНКИ
52
+ # ============================================================
53
+ def compute_reward(text):
54
+ """Вычисляет 'позитивность' текста с помощью Reward модели"""
55
+ inputs = reward_tokenizer(
56
+ text, truncation=True, max_length=512,
57
+ padding=True, return_tensors="pt"
58
+ ).to(DEVICE)
59
+ with torch.no_grad():
60
+ score = reward_model(**inputs).logits[0, 0].item()
61
+ return score
62
+
63
+ def generate_text(model, tokenizer, prompt, max_new_tokens, temperature, top_p):
64
+ """Генерирует продолжение текста"""
65
+ inputs = tokenizer(prompt, return_tensors="pt").to(DEVICE)
66
+ with torch.no_grad():
67
+ outputs = model.generate(
68
+ **inputs,
69
+ max_new_tokens=max_new_tokens,
70
+ do_sample=True,
71
+ temperature=temperature,
72
+ top_p=top_p,
73
+ pad_token_id=tokenizer.eos_token_id
74
+ )
75
+ return tokenizer.decode(outputs[0], skip_special_tokens=True)
76
+
77
+ # ============================================================
78
+ # ИНТЕРФЕЙС ПРИЛОЖЕНИЯ
79
+ # ============================================================
80
+ st.sidebar.header("Параметры генерации")
81
+ max_tokens = st.sidebar.slider("Max New Tokens", 10, 150, 80)
82
+ temperature = st.sidebar.slider("Temperature", 0.1, 1.5, 0.8)
83
+ top_p = st.sidebar.slider("Top-p", 0.1, 1.0, 0.95)
84
+
85
+ st.write("---")
86
+ st.subheader("📝 Введите начало отзыва")
87
+
88
+ predefined_prompts = [
89
+ "This movie was",
90
+ "I went to the cinema and",
91
+ "The acting in this film",
92
+ "I absolutely",
93
+ "What a terrible",
94
+ "Свой вариант..."
95
+ ]
96
+
97
+ selected_prompt = st.selectbox("Выберите шаблон или напишите свой:", predefined_prompts)
98
+
99
+ if selected_prompt == "Свой вариант...":
100
+ user_prompt = st.text_input("Ваш текст:", "The director tried to")
101
+ else:
102
+ user_prompt = selected_prompt
103
+
104
+ if st.button("🚀 Сгенерировать отзыв", type="primary"):
105
+ with st.spinner("Модели думают..."):
106
+ # Генерация оригинальной моделью
107
+ orig_text = generate_text(orig_model, orig_tokenizer, user_prompt, max_tokens, temperature, top_p)
108
+ orig_reward = compute_reward(orig_text)
109
+
110
+ # Генерация RLHF моделью
111
+ rlhf_text = generate_text(rlhf_model, orig_tokenizer, user_prompt, max_tokens, temperature, top_p)
112
+ rlhf_reward = compute_reward(rlhf_text)
113
+
114
+ # Визуализация результатов в две колонки
115
+ col1, col2 = st.columns(2)
116
+
117
+ with col1:
118
+ st.markdown("### 🤖 Original GPT-2")
119
+ st.metric(label="Reward Score (чем больше, тем позитивнее)", value=f"{orig_reward:+.3f}")
120
+ st.info(orig_text)
121
+
122
+ with col2:
123
+ st.markdown("### ✨ RLHF Model (PPO)")
124
+ delta = rlhf_reward - orig_reward
125
+ st.metric(label="Reward Score (чем больше, тем позитивнее)", value=f"{rlhf_reward:+.3f}", delta=f"{delta:+.3f} vs Orig")
126
+ st.success(rlhf_text)
127
+
128
+ st.markdown("---")
129
+ st.caption("💡 *Подсказка: RLHF модель (справа) должна стараться уводить текст в позитивное русло, даже если вы начинаете отзыв со слов 'What a terrible'.*")
ppo_model_trained/config.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "lvwerra/gpt2-imdb",
3
+ "activation_function": "gelu_new",
4
+ "architectures": [
5
+ "GPT2LMHeadModel"
6
+ ],
7
+ "attn_pdrop": 0.1,
8
+ "bos_token_id": 50256,
9
+ "embd_pdrop": 0.1,
10
+ "eos_token_id": 50256,
11
+ "initializer_range": 0.02,
12
+ "layer_norm_epsilon": 1e-05,
13
+ "model_type": "gpt2",
14
+ "n_ctx": 1024,
15
+ "n_embd": 768,
16
+ "n_head": 12,
17
+ "n_inner": null,
18
+ "n_layer": 12,
19
+ "n_positions": 1024,
20
+ "output_past": true,
21
+ "reorder_and_upcast_attn": false,
22
+ "resid_pdrop": 0.1,
23
+ "scale_attn_by_inverse_layer_idx": false,
24
+ "scale_attn_weights": true,
25
+ "summary_activation": null,
26
+ "summary_first_dropout": 0.1,
27
+ "summary_proj_to_labels": true,
28
+ "summary_type": "cls_index",
29
+ "summary_use_proj": true,
30
+ "torch_dtype": "float32",
31
+ "transformers_version": "4.44.2",
32
+ "use_cache": true,
33
+ "vocab_size": 50257
34
+ }
ppo_model_trained/generation_config.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {
2
+ "_from_model_config": true,
3
+ "bos_token_id": 50256,
4
+ "eos_token_id": 50256,
5
+ "transformers_version": "4.44.2"
6
+ }
ppo_model_trained/merges.txt ADDED
The diff for this file is too large to render. See raw diff
 
ppo_model_trained/special_tokens_map.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "bos_token": {
3
+ "content": "<|endoftext|>",
4
+ "lstrip": false,
5
+ "normalized": true,
6
+ "rstrip": false,
7
+ "single_word": false
8
+ },
9
+ "eos_token": {
10
+ "content": "<|endoftext|>",
11
+ "lstrip": false,
12
+ "normalized": true,
13
+ "rstrip": false,
14
+ "single_word": false
15
+ },
16
+ "pad_token": "<|endoftext|>",
17
+ "unk_token": {
18
+ "content": "<|endoftext|>",
19
+ "lstrip": false,
20
+ "normalized": true,
21
+ "rstrip": false,
22
+ "single_word": false
23
+ }
24
+ }
ppo_model_trained/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
ppo_model_trained/tokenizer_config.json ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "add_bos_token": false,
3
+ "add_prefix_space": false,
4
+ "added_tokens_decoder": {
5
+ "50256": {
6
+ "content": "<|endoftext|>",
7
+ "lstrip": false,
8
+ "normalized": true,
9
+ "rstrip": false,
10
+ "single_word": false,
11
+ "special": true
12
+ }
13
+ },
14
+ "bos_token": "<|endoftext|>",
15
+ "clean_up_tokenization_spaces": true,
16
+ "eos_token": "<|endoftext|>",
17
+ "errors": "replace",
18
+ "max_len": 1024,
19
+ "model_max_length": 1024,
20
+ "pad_token": "<|endoftext|>",
21
+ "tokenizer_class": "GPT2Tokenizer",
22
+ "unk_token": "<|endoftext|>"
23
+ }
ppo_model_trained/vocab.json ADDED
The diff for this file is too large to render. See raw diff
 
reward_model_trained/config.json ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_name_or_path": "distilbert-base-cased",
3
+ "activation": "gelu",
4
+ "architectures": [
5
+ "DistilBertForSequenceClassification"
6
+ ],
7
+ "attention_dropout": 0.1,
8
+ "dim": 768,
9
+ "dropout": 0.1,
10
+ "hidden_dim": 3072,
11
+ "id2label": {
12
+ "0": "LABEL_0"
13
+ },
14
+ "initializer_range": 0.02,
15
+ "label2id": {
16
+ "LABEL_0": 0
17
+ },
18
+ "max_position_embeddings": 512,
19
+ "model_type": "distilbert",
20
+ "n_heads": 12,
21
+ "n_layers": 6,
22
+ "output_past": true,
23
+ "pad_token_id": 0,
24
+ "qa_dropout": 0.1,
25
+ "seq_classif_dropout": 0.2,
26
+ "sinusoidal_pos_embds": false,
27
+ "tie_weights_": true,
28
+ "torch_dtype": "float32",
29
+ "transformers_version": "4.44.2",
30
+ "vocab_size": 28996
31
+ }
reward_model_trained/special_tokens_map.json ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "cls_token": "[CLS]",
3
+ "eos_token": "[SEP]",
4
+ "mask_token": "[MASK]",
5
+ "pad_token": "[PAD]",
6
+ "sep_token": "[SEP]",
7
+ "unk_token": "[UNK]"
8
+ }
reward_model_trained/tokenizer.json ADDED
The diff for this file is too large to render. See raw diff
 
reward_model_trained/tokenizer_config.json ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "added_tokens_decoder": {
3
+ "0": {
4
+ "content": "[PAD]",
5
+ "lstrip": false,
6
+ "normalized": false,
7
+ "rstrip": false,
8
+ "single_word": false,
9
+ "special": true
10
+ },
11
+ "100": {
12
+ "content": "[UNK]",
13
+ "lstrip": false,
14
+ "normalized": false,
15
+ "rstrip": false,
16
+ "single_word": false,
17
+ "special": true
18
+ },
19
+ "101": {
20
+ "content": "[CLS]",
21
+ "lstrip": false,
22
+ "normalized": false,
23
+ "rstrip": false,
24
+ "single_word": false,
25
+ "special": true
26
+ },
27
+ "102": {
28
+ "content": "[SEP]",
29
+ "lstrip": false,
30
+ "normalized": false,
31
+ "rstrip": false,
32
+ "single_word": false,
33
+ "special": true
34
+ },
35
+ "103": {
36
+ "content": "[MASK]",
37
+ "lstrip": false,
38
+ "normalized": false,
39
+ "rstrip": false,
40
+ "single_word": false,
41
+ "special": true
42
+ }
43
+ },
44
+ "clean_up_tokenization_spaces": true,
45
+ "cls_token": "[CLS]",
46
+ "do_lower_case": false,
47
+ "eos_token": "[SEP]",
48
+ "mask_token": "[MASK]",
49
+ "model_max_length": 512,
50
+ "pad_token": "[PAD]",
51
+ "sep_token": "[SEP]",
52
+ "strip_accents": null,
53
+ "tokenize_chinese_chars": true,
54
+ "tokenizer_class": "DistilBertTokenizer",
55
+ "unk_token": "[UNK]"
56
+ }
reward_model_trained/vocab.txt ADDED
The diff for this file is too large to render. See raw diff