KoDer123 commited on
Commit
81fa685
·
verified ·
1 Parent(s): 64f9530

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +110 -44
app.py CHANGED
@@ -5,6 +5,9 @@ import os
5
  import shutil
6
  import time
7
  import logging
 
 
 
8
 
9
  # Настройка логирования
10
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
@@ -20,17 +23,26 @@ else:
20
  # Информация о системе и CUDA
21
  logger.info("===== Запуск приложения =====")
22
  logger.info(f"PyTorch: {torch.__version__}")
23
- logger.info(f"CUDA доступен: {torch.cuda.is_available()}")
24
 
25
- if torch.cuda.is_available():
 
 
 
 
26
  try:
27
  cuda_device_count = torch.cuda.device_count()
28
  logger.info(f"Количество CUDA устройств: {cuda_device_count}")
29
  for i in range(cuda_device_count):
30
  logger.info(f"CUDA устройство {i}: {torch.cuda.get_device_name(i)}")
31
  logger.info(f"Текущее CUDA устройство: {torch.cuda.current_device()}")
 
 
 
 
 
32
  except Exception as e:
33
  logger.warning(f"Ошибка при получении информации о CUDA: {e}")
 
34
  else:
35
  logger.info("CUDA недоступен, будет использоваться CPU")
36
 
@@ -70,8 +82,15 @@ logger.info("Информация о дисках перед загрузкой:
70
  check_disk_space("/")
71
  check_disk_space(DISK_DIR)
72
 
73
- # Загрузка модели и токенизатора
74
- model_name = "KoDer123/Nerealnost_8M"
 
 
 
 
 
 
 
75
 
76
  # Глобальные переменные для модели
77
  model = None
@@ -81,15 +100,40 @@ is_model_loaded = False
81
  # Переопределяем EOS_TOKEN для случая, когда токенизатор не загружен
82
  DEFAULT_EOS_TOKEN = "</s>"
83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
84
  # Функция для загрузки модели
85
  def load_model():
86
  global model, tokenizer, is_model_loaded
87
 
88
  try:
 
 
 
89
  logger.info("Загружаем токенизатор...")
90
  tokenizer = AutoTokenizer.from_pretrained(
91
  model_name,
92
- token=HF_TOKEN, # Добавляем токен для доступа к закрытой модели
93
  cache_dir=CACHE_DIR,
94
  local_files_only=False
95
  )
@@ -103,18 +147,21 @@ def load_model():
103
  model_kwargs = {
104
  "cache_dir": CACHE_DIR,
105
  "trust_remote_code": True,
106
- "token": HF_TOKEN # Добавляем токен для доступа к закрытой модели
107
  }
108
 
109
  # Проверяем доступность CUDA
110
- if torch.cuda.is_available():
111
  logger.info("Загружаем модель в режиме GPU...")
112
  model_kwargs.update({
113
  "torch_dtype": torch.float16,
 
114
  })
115
  else:
116
  logger.info("Загружаем модель в режиме CPU...")
117
- # Без параметров device_map и low_cpu_mem_usage
 
 
118
 
119
  # Загружаем модель
120
  model = AutoModelForCausalLM.from_pretrained(
@@ -122,14 +169,15 @@ def load_model():
122
  **model_kwargs
123
  )
124
 
125
- # Переносим модель на доступное устройство
126
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
127
- model = model.to(device)
128
 
129
- logger.info(f"Модель успешно загружена на устройство: {device}")
 
130
 
131
  is_model_loaded = True
132
- return "Модель успешно загружена"
133
  except Exception as e:
134
  error_msg = str(e)
135
  logger.error(f"Ошибка загрузки модели: {error_msg}")
@@ -160,6 +208,7 @@ def respond(
160
  max_tokens,
161
  temperature,
162
  top_p,
 
163
  ):
164
  global model, tokenizer, is_model_loaded
165
 
@@ -170,6 +219,9 @@ def respond(
170
  else:
171
  return "Модель не загружена или произошла ошибка при загрузке. Проверьте логи для получения дополнительной информации."
172
 
 
 
 
173
  # Замеряем время
174
  start_time = time.time()
175
 
@@ -187,35 +239,41 @@ def respond(
187
  logger.info(f"Генерируем ответ на запрос: '{message[:50]}...' (длина промпта: {len(full_prompt)})")
188
 
189
  try:
190
- # Токенизация входных данных
191
- inputs = tokenizer(full_prompt, return_tensors="pt").to(model.device)
192
-
193
- # Генерация ответа
194
- outputs = model.generate(
195
- inputs.input_ids, # Передаем только input_ids, не весь словарь
196
- max_new_tokens=max_tokens,
197
- temperature=temperature,
198
- top_p=top_p,
199
- do_sample=True,
200
- pad_token_id=tokenizer.pad_token_id,
201
- )
202
-
203
- # Декодирование полного вывода
204
- generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
205
-
206
- # Извлекаем только часть после "Ассистент: "
207
- response_start = generated_text.rfind("Ассистент: ") + len("Ассистент: ")
208
- if response_start >= len("Ассистент: "): # Проверяем, что "Ассистент: " найден
209
- response = generated_text[response_start:].strip()
210
- else:
211
- # Если не найдено, возвращаем весь текст
212
- response = generated_text.strip()
 
 
213
 
214
  end_time = time.time()
215
  generation_time = end_time - start_time
216
  logger.info(f"Генерация заняла {generation_time:.2f} секунд. Получен ответ длиной {len(response)} символов")
217
 
218
  return response
 
 
 
 
219
  except Exception as e:
220
  logger.error(f"Ошибка при генерации ответа: {str(e)}")
221
  return f"Произошла ошибка при генерации ответа: {str(e)}"
@@ -236,7 +294,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
236
 
237
  with gr.Row():
238
  with gr.Column(scale=4):
239
- chatbot = gr.Chatbot(label="Диалог", type="messages") # Исправление типа чатбота
240
  user_input = gr.Textbox(
241
  placeholder="Введите ваш вопрос здесь...",
242
  label="Ваш вопрос",
@@ -256,14 +314,14 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
256
  )
257
  max_tokens = gr.Slider(
258
  minimum=1,
259
- maximum=2048,
260
- value=512,
261
  step=1,
262
  label="Максимальное число токенов"
263
  )
264
  temperature = gr.Slider(
265
  minimum=0.1,
266
- maximum=4.0,
267
  value=0.7,
268
  step=0.1,
269
  label="Температура"
@@ -271,15 +329,22 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
271
  top_p = gr.Slider(
272
  minimum=0.1,
273
  maximum=1.0,
274
- value=0.95,
275
  step=0.05,
276
  label="Top-p"
277
  )
 
 
 
 
 
 
 
278
 
279
- with gr.Accordion("Информация", open=True):
280
  info_text = gr.Markdown(f"""
281
  * **Модель**: {model_name}
282
- * **Режим работы**: {"GPU" if torch.cuda.is_available() else "CPU"}
283
  * **Директория для кэша**: {CACHE_DIR}
284
  * **Статус загрузки**: {"Успешно" if is_model_loaded else "Ошибка"}
285
  * **API токен**: {"Настроен" if HF_TOKEN else "Отсутствует"}
@@ -308,7 +373,8 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
308
  system_msg.value,
309
  max_tokens.value,
310
  temperature.value,
311
- top_p.value
 
312
  )
313
 
314
  # Добавляем в историю и возвращаем
 
5
  import shutil
6
  import time
7
  import logging
8
+ import gc
9
+ import signal
10
+ from contextlib import contextmanager
11
 
12
  # Настройка логирования
13
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
 
23
  # Информация о системе и CUDA
24
  logger.info("===== Запуск приложения =====")
25
  logger.info(f"PyTorch: {torch.__version__}")
 
26
 
27
+ # Проверка CUDA и соответствующие логи
28
+ cuda_available = torch.cuda.is_available()
29
+ logger.info(f"CUDA доступен: {cuda_available}")
30
+
31
+ if cuda_available:
32
  try:
33
  cuda_device_count = torch.cuda.device_count()
34
  logger.info(f"Количество CUDA устройств: {cuda_device_count}")
35
  for i in range(cuda_device_count):
36
  logger.info(f"CUDA устройство {i}: {torch.cuda.get_device_name(i)}")
37
  logger.info(f"Текущее CUDA устройство: {torch.cuda.current_device()}")
38
+
39
+ # Проверка доступной памяти
40
+ for i in range(cuda_device_count):
41
+ free_mem = torch.cuda.get_device_properties(i).total_memory - torch.cuda.memory_allocated(i)
42
+ logger.info(f"Устройство {i}: свободно {free_mem / 1024**3:.2f} ГБ из {torch.cuda.get_device_properties(i).total_memory / 1024**3:.2f} ГБ")
43
  except Exception as e:
44
  logger.warning(f"Ошибка при получении информации о CUDA: {e}")
45
+ cuda_available = False
46
  else:
47
  logger.info("CUDA недоступен, будет использоваться CPU")
48
 
 
82
  check_disk_space("/")
83
  check_disk_space(DISK_DIR)
84
 
85
+ # Настройка модели - выбор в зависимости от доступных ресурсов
86
+ if cuda_available:
87
+ # Для режима GPU используем более крупную модель (если она есть)
88
+ model_name = "KoDer123/Nerealnost_8M" # Ваша основная модель
89
+ else:
90
+ # Для режима CPU можно выбрать более легкую модель
91
+ model_name = "KoDer123/Nerealnost_8M" # Можно заменить на более легкую, если нужно
92
+
93
+ logger.info(f"Выбрана модель: {model_name}")
94
 
95
  # Глобальные переменные для модели
96
  model = None
 
100
  # Переопределяем EOS_TOKEN для случая, когда токенизатор не загружен
101
  DEFAULT_EOS_TOKEN = "</s>"
102
 
103
+ # Класс таймаута для ограничения времени генерации
104
+ class TimeoutException(Exception):
105
+ pass
106
+
107
+ @contextmanager
108
+ def time_limit(seconds):
109
+ def signal_handler(signum, frame):
110
+ raise TimeoutException("Timeout")
111
+
112
+ signal.signal(signal.SIGALRM, signal_handler)
113
+ signal.alarm(seconds)
114
+ try:
115
+ yield
116
+ finally:
117
+ signal.alarm(0)
118
+
119
+ # Функция для очистки памяти
120
+ def clear_memory():
121
+ if cuda_available:
122
+ torch.cuda.empty_cache()
123
+ gc.collect()
124
+
125
  # Функция для загрузки модели
126
  def load_model():
127
  global model, tokenizer, is_model_loaded
128
 
129
  try:
130
+ # Очищаем память перед загрузкой
131
+ clear_memory()
132
+
133
  logger.info("Загружаем токенизатор...")
134
  tokenizer = AutoTokenizer.from_pretrained(
135
  model_name,
136
+ token=HF_TOKEN,
137
  cache_dir=CACHE_DIR,
138
  local_files_only=False
139
  )
 
147
  model_kwargs = {
148
  "cache_dir": CACHE_DIR,
149
  "trust_remote_code": True,
150
+ "token": HF_TOKEN
151
  }
152
 
153
  # Проверяем доступность CUDA
154
+ if cuda_available:
155
  logger.info("Загружаем модель в режиме GPU...")
156
  model_kwargs.update({
157
  "torch_dtype": torch.float16,
158
+ "device_map": "auto", # Автоматически распределить по устройствам
159
  })
160
  else:
161
  logger.info("Загружаем модель в режиме CPU...")
162
+ model_kwargs.update({
163
+ "torch_dtype": torch.float32,
164
+ })
165
 
166
  # Загружаем модель
167
  model = AutoModelForCausalLM.from_pretrained(
 
169
  **model_kwargs
170
  )
171
 
172
+ # Если GPU недоступен, явно переносим модель на CPU
173
+ if not cuda_available:
174
+ model = model.to("cpu")
175
 
176
+ device_info = next(model.parameters()).device
177
+ logger.info(f"Модель успешно загружена на устройство: {device_info}")
178
 
179
  is_model_loaded = True
180
+ return f"Модель успешно загружена на {device_info}"
181
  except Exception as e:
182
  error_msg = str(e)
183
  logger.error(f"Ошибка загрузки модели: {error_msg}")
 
208
  max_tokens,
209
  temperature,
210
  top_p,
211
+ generation_timeout,
212
  ):
213
  global model, tokenizer, is_model_loaded
214
 
 
219
  else:
220
  return "Модель не загружена или произошла ошибка при загрузке. Проверьте логи для получения дополнительной информации."
221
 
222
+ # Очищаем память перед генерацией
223
+ clear_memory()
224
+
225
  # Замеряем время
226
  start_time = time.time()
227
 
 
239
  logger.info(f"Генерируем ответ на запрос: '{message[:50]}...' (длина промпта: {len(full_prompt)})")
240
 
241
  try:
242
+ # Используем таймаут для генерации
243
+ with time_limit(generation_timeout):
244
+ # Токенизация входных данных
245
+ inputs = tokenizer(full_prompt, return_tensors="pt").to(model.device)
246
+
247
+ # Генерация ответа
248
+ outputs = model.generate(
249
+ inputs.input_ids,
250
+ max_new_tokens=max_tokens,
251
+ temperature=temperature,
252
+ top_p=top_p,
253
+ do_sample=True,
254
+ pad_token_id=tokenizer.pad_token_id,
255
+ )
256
+
257
+ # Декодирование полного вывода
258
+ generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
259
+
260
+ # Извлекаем только часть после "Ассистент: "
261
+ response_start = generated_text.rfind("Ассистент: ") + len("Ассистент: ")
262
+ if response_start >= len("Ассистент: "): # Проверяем, что "Ассистент: " найден
263
+ response = generated_text[response_start:].strip()
264
+ else:
265
+ # Если не найдено, возвращаем весь текст
266
+ response = generated_text.strip()
267
 
268
  end_time = time.time()
269
  generation_time = end_time - start_time
270
  logger.info(f"Генерация заняла {generation_time:.2f} секунд. Получен ответ длиной {len(response)} символов")
271
 
272
  return response
273
+
274
+ except TimeoutException:
275
+ logger.warning(f"Генерация превысила лимит времени ({generation_timeout} секунд)")
276
+ return f"Генерация ответа превысила лимит времени ({generation_timeout} секунд). Попробуйте уменьшить количество токенов или задать более простой вопрос."
277
  except Exception as e:
278
  logger.error(f"Ошибка при генерации ответа: {str(e)}")
279
  return f"Произошла ошибка при генерации ответа: {str(e)}"
 
294
 
295
  with gr.Row():
296
  with gr.Column(scale=4):
297
+ chatbot = gr.Chatbot(label="Диалог", type="messages")
298
  user_input = gr.Textbox(
299
  placeholder="Введите ваш вопрос здесь...",
300
  label="Ваш вопрос",
 
314
  )
315
  max_tokens = gr.Slider(
316
  minimum=1,
317
+ maximum=1024,
318
+ value=64 if not cuda_available else 256, # Меньше токенов для CPU
319
  step=1,
320
  label="Максимальное число токенов"
321
  )
322
  temperature = gr.Slider(
323
  minimum=0.1,
324
+ maximum=1.2,
325
  value=0.7,
326
  step=0.1,
327
  label="Температура"
 
329
  top_p = gr.Slider(
330
  minimum=0.1,
331
  maximum=1.0,
332
+ value=0.9,
333
  step=0.05,
334
  label="Top-p"
335
  )
336
+ generation_timeout = gr.Slider(
337
+ minimum=10,
338
+ maximum=300,
339
+ value=60 if cuda_available else 120, # Больше времени для CPU
340
+ step=10,
341
+ label="Таймаут генерации (секунды)"
342
+ )
343
 
344
+ with gr.Accordion("Информация о системе", open=True):
345
  info_text = gr.Markdown(f"""
346
  * **Модель**: {model_name}
347
+ * **Режим работы**: {"GPU" if cuda_available else "CPU"}
348
  * **Директория для кэша**: {CACHE_DIR}
349
  * **Статус загрузки**: {"Успешно" if is_model_loaded else "Ошибка"}
350
  * **API токен**: {"Настроен" if HF_TOKEN else "Отсутствует"}
 
373
  system_msg.value,
374
  max_tokens.value,
375
  temperature.value,
376
+ top_p.value,
377
+ generation_timeout.value
378
  )
379
 
380
  # Добавляем в историю и возвращаем