Yuchan5386 commited on
Commit
9cad8b1
·
verified ·
1 Parent(s): 9e90de0

Update api.py

Browse files
Files changed (1) hide show
  1. api.py +162 -154
api.py CHANGED
@@ -1,139 +1,138 @@
1
- from fastapi import FastAPI, Request
2
- from fastapi.responses import StreamingResponse
3
- import asyncio
4
- import numpy as np
5
- import tensorflow as tf
6
- from tensorflow.keras import layers
7
- import sentencepiece as spm
8
-
9
- app = FastAPI()
10
-
11
- # SentencePiece 로드
12
- sp = spm.SentencePieceProcessor()
13
- sp.load("kolig_unigram.model")
14
-
15
- pad_id = sp.piece_to_id("<pad>")
16
- if pad_id == -1: pad_id = 0
17
- start_id = sp.piece_to_id("<start>")
18
- if start_id == -1: start_id = 1
19
- end_id = sp.piece_to_id("<end>")
20
- if end_id == -1: end_id = 2
21
- unk_id = sp.piece_to_id("<unk>")
22
- if unk_id == -1: unk_id = 3
23
-
24
- vocab_size = sp.get_piece_size()
25
- max_len = 100
26
-
27
- def text_to_ids(text):
28
- return sp.encode(text, out_type=int)
29
-
30
- def ids_to_text(ids):
31
- return sp.decode(ids)
32
-
33
- class RotaryPositionalEmbedding(layers.Layer):
34
- def __init__(self, dim):
35
- super().__init__()
36
- inv_freq = 1.0 / (10000 ** (np.arange(0, dim, 2) / dim))
37
- self.inv_freq = tf.constant(inv_freq, dtype=tf.float32)
38
-
39
- def call(self, x):
40
- batch, heads, seq_len, depth = tf.unstack(tf.shape(x))
41
- t = tf.range(seq_len, dtype=tf.float32)
42
- freqs = tf.einsum('i,j->ij', t, self.inv_freq)
43
- emb_sin = tf.sin(freqs)
44
- emb_cos = tf.cos(freqs)
45
- emb_cos = tf.reshape(emb_cos, [1, 1, seq_len, -1])
46
- emb_sin = tf.reshape(emb_sin, [1, 1, seq_len, -1])
47
- x1 = x[..., ::2]
48
- x2 = x[..., 1::2]
49
- x_rotated = tf.stack([
50
- x1 * emb_cos - x2 * emb_sin,
51
- x1 * emb_sin + x2 * emb_cos
52
- ], axis=-1)
53
- x_rotated = tf.reshape(x_rotated, tf.shape(x))
54
- return x_rotated
55
-
56
- class SwiGLU(tf.keras.layers.Layer):
57
- def __init__(self, d_model, d_ff):
58
- super().__init__()
59
- self.proj = tf.keras.layers.Dense(d_ff * 2)
60
- self.out = tf.keras.layers.Dense(d_model)
61
-
62
- def call(self, x):
63
- x_proj = self.proj(x)
64
- x_val, x_gate = tf.split(x_proj, 2, axis=-1)
65
- return self.out(x_val * tf.nn.silu(x_gate))
66
-
67
- class GPTBlock(tf.keras.layers.Layer):
68
- def __init__(self, d_model, d_ff, num_heads=8, dropout_rate=0.1, adapter_dim=64):
69
- super().__init__()
70
- self.ln1 = tf.keras.layers.LayerNormalization(epsilon=1e-5)
71
- self.mha = tf.keras.layers.MultiHeadAttention(num_heads=num_heads, key_dim=d_model // num_heads)
72
- self.dropout1 = tf.keras.layers.Dropout(dropout_rate)
73
- self.adapter_down = tf.keras.layers.Dense(adapter_dim, activation='gelu')
74
- self.adapter_up = tf.keras.layers.Dense(d_model)
75
-
76
- self.ln2 = tf.keras.layers.LayerNormalization(epsilon=1e-5)
77
- self.ffn = SwiGLU(d_model, d_ff)
78
- self.dropout2 = tf.keras.layers.Dropout(dropout_rate)
79
- self.rope = RotaryPositionalEmbedding(d_model // num_heads)
80
-
81
- def call(self, x, training=False):
82
- x_norm = self.ln1(x)
83
- b, s, _ = tf.shape(x_norm)[0], tf.shape(x_norm)[1], tf.shape(x_norm)[2]
84
- h = self.mha.num_heads
85
- d = x_norm.shape[-1] // h
86
-
87
- qkv = tf.reshape(x_norm, [b, s, h, d])
88
- qkv = tf.transpose(qkv, [0, 2, 1, 3])
89
- q = self.rope(qkv)
90
- k = self.rope(qkv)
91
- q = tf.reshape(tf.transpose(q, [0, 2, 1, 3]), [b, s, h * d])
92
- k = tf.reshape(tf.transpose(k, [0, 2, 1, 3]), [b, s, h * d])
93
-
94
- attn_out = self.mha(query=q, value=x_norm, key=k, use_causal_mask=True, training=training)
95
- attn_out = self.dropout1(attn_out, training=training)
96
-
97
- adapter_out = self.adapter_up(self.adapter_down(attn_out))
98
- attn_out = attn_out + adapter_out
99
-
100
- x = x + attn_out
101
- ffn_out = self.ffn(self.ln2(x))
102
- x = x + self.dropout2(ffn_out, training=training)
103
- return x
104
-
105
- class InteractGPT(tf.keras.Model):
106
- def __init__(self, vocab_size, seq_len, d_model, d_ff, n_layers, num_heads=8, dropout_rate=0.1):
107
- super().__init__()
108
- self.token_embedding = tf.keras.layers.Embedding(vocab_size, d_model)
109
- self.blocks = [GPTBlock(d_model, d_ff, num_heads, dropout_rate) for _ in range(n_layers)]
110
- self.ln_f = tf.keras.layers.LayerNormalization(epsilon=1e-5)
111
-
112
- def call(self, x, training=False):
113
- x = self.token_embedding(x)
114
- for block in self.blocks:
115
- x = block(x, training=training)
116
- x = self.ln_f(x)
117
- logits = tf.matmul(x, self.token_embedding.embeddings, transpose_b=True)
118
- return logits
119
-
120
- model = InteractGPT(vocab_size=vocab_size, seq_len=max_len, d_model=256, d_ff=1024, n_layers=6)
121
-
122
- dummy_input = tf.zeros((1, max_len), dtype=tf.int32)
123
- _ = model(dummy_input)
124
- model.load_weights("InteractGPT.weights.h5")
125
- print("모델 가중치 로드 완료!")
126
-
127
-
128
- async def generate_text_mirostat_top_p_with_buffer(model, prompt, max_len=100, max_gen=98,
129
  temperature=1.0, min_len=20,
130
- repetition_penalty=1.2, eta=0.1, m=100, p=0.9, buffer_size=3):
131
  model_input = text_to_ids(f"<start> {prompt} <sep>")
132
  model_input = model_input[:max_len]
133
  generated = list(model_input)
134
 
135
  tau = 5.0 # 초기 목표 surprise
136
- buffer_tokens = []
137
 
138
  for step in range(max_gen):
139
  pad_length = max(0, max_len - len(generated))
@@ -149,26 +148,32 @@ async def generate_text_mirostat_top_p_with_buffer(model, prompt, max_len=100, m
149
  for token_id, count in token_counts.items():
150
  next_token_logits[token_id] /= (repetition_penalty ** count)
151
 
 
152
  if len(generated) >= min_len:
153
  next_token_logits[end_id] -= 5.0
154
  next_token_logits[pad_id] -= 10.0
155
 
 
156
  next_token_logits = next_token_logits / temperature
157
 
 
158
  logits_stable = next_token_logits - np.max(next_token_logits)
159
  probs = np.exp(logits_stable)
160
  probs /= probs.sum()
161
 
 
162
  sorted_indices = np.argsort(-probs)
163
  top_indices = sorted_indices[:m]
164
  top_probs = probs[top_indices]
165
  top_probs /= top_probs.sum()
166
 
 
167
  sampled_index = np.random.choice(top_indices, p=top_probs)
168
  sampled_prob = probs[sampled_index]
169
  observed_surprise = -np.log(sampled_prob + 1e-9)
170
  tau += eta * (observed_surprise - tau)
171
 
 
172
  sorted_top_indices = top_indices[np.argsort(-top_probs)]
173
  sorted_top_probs = np.sort(top_probs)[::-1]
174
  cumulative_probs = np.cumsum(sorted_top_probs)
@@ -177,32 +182,35 @@ async def generate_text_mirostat_top_p_with_buffer(model, prompt, max_len=100, m
177
  filtered_probs = sorted_top_probs[:cutoff]
178
  filtered_probs /= filtered_probs.sum()
179
 
 
180
  final_token = np.random.choice(filtered_indices, p=filtered_probs)
 
181
 
182
- if final_token == end_id:
183
- # 버퍼에 남은 거 다 출력
184
- if buffer_tokens:
185
- decoded = sp.decode(buffer_tokens)
186
- for token in ["<start>", "<sep>", "<end>"]:
187
- decoded = decoded.replace(token, "")
188
- yield decoded.strip()
189
- break
190
 
191
- if final_token in [start_id, pad_id] or sp.id_to_piece(final_token) == "<sep>":
192
- continue
193
 
194
- generated.append(int(final_token))
195
- buffer_tokens.append(final_token)
196
-
197
- if len(buffer_tokens) >= buffer_size or sp.id_to_piece(final_token).endswith("▁"):
198
- # 띄어쓰기 있는 토큰 나오거나 버퍼 꽉 찼으면 출력
199
- decoded = sp.decode(buffer_tokens)
200
- for token in ["<start>", "<sep>", "<end>"]:
201
- decoded = decoded.replace(token, "")
202
- yield decoded.strip()
203
- buffer_tokens = []
 
 
 
 
 
 
 
 
204
 
205
- @app.get("/generate")
206
- async def generate(request: Request):
207
- prompt = request.query_params.get("prompt", "안녕하세요")
208
- return StreamingResponse(generate_text_mirostat_top_p_with_buffer(model, prompt), media_type="text/plain")
 
1
+ from fastapi import FastAPI, Request
2
+ from fastapi.responses import StreamingResponse
3
+ import asyncio
4
+ import json
5
+ import numpy as np
6
+ import tensorflow as tf
7
+ from tensorflow.keras import layers
8
+ import sentencepiece as spm
9
+ import requests
10
+
11
+ app = FastAPI()
12
+
13
+ sp = spm.SentencePieceProcessor()
14
+ sp.load("kolig_unigram.model")
15
+
16
+ pad_id = sp.piece_to_id("<pad>")
17
+ if pad_id == -1: pad_id = 0
18
+ start_id = sp.piece_to_id("<start>")
19
+ if start_id == -1: start_id = 1
20
+ end_id = sp.piece_to_id("< end >")
21
+ if end_id == -1: end_id = 2
22
+ unk_id = sp.piece_to_id("<unk>")
23
+ if unk_id == -1: unk_id = 3
24
+
25
+ vocab_size = sp.get_piece_size()
26
+ max_len = 100
27
+
28
+ def text_to_ids(text):
29
+ return sp.encode(text, out_type=int)
30
+
31
+ def ids_to_text(ids):
32
+ return sp.decode(ids)
33
+
34
+ class RotaryPositionalEmbedding(layers.Layer):
35
+ def __init__(self, dim):
36
+ super().__init__()
37
+ inv_freq = 1.0 / (10000 ** (np.arange(0, dim, 2) / dim))
38
+ self.inv_freq = tf.constant(inv_freq, dtype=tf.float32)
39
+
40
+ def call(self, x):
41
+ batch, heads, seq_len, depth = tf.unstack(tf.shape(x))
42
+ t = tf.range(seq_len, dtype=tf.float32)
43
+ freqs = tf.einsum('i,j->ij', t, self.inv_freq)
44
+ emb_sin = tf.sin(freqs)
45
+ emb_cos = tf.cos(freqs)
46
+ emb_cos = tf.reshape(emb_cos, [1, 1, seq_len, -1])
47
+ emb_sin = tf.reshape(emb_sin, [1, 1, seq_len, -1])
48
+ x1 = x[..., ::2]
49
+ x2 = x[..., 1::2]
50
+ x_rotated = tf.stack([
51
+ x1 * emb_cos - x2 * emb_sin,
52
+ x1 * emb_sin + x2 * emb_cos
53
+ ], axis=-1)
54
+ x_rotated = tf.reshape(x_rotated, tf.shape(x))
55
+ return x_rotated
56
+
57
+ class SwiGLU(tf.keras.layers.Layer):
58
+ def __init__(self, d_model, d_ff):
59
+ super().__init__()
60
+ self.proj = tf.keras.layers.Dense(d_ff * 2)
61
+ self.out = tf.keras.layers.Dense(d_model)
62
+
63
+ def call(self, x):
64
+ x_proj = self.proj(x)
65
+ x_val, x_gate = tf.split(x_proj, 2, axis=-1)
66
+ return self.out(x_val * tf.nn.silu(x_gate))
67
+
68
+ class GPTBlock(tf.keras.layers.Layer):
69
+ def __init__(self, d_model, d_ff, num_heads=8, dropout_rate=0.1, adapter_dim=64):
70
+ super().__init__()
71
+ self.ln1 = tf.keras.layers.LayerNormalization(epsilon=1e-5)
72
+ self.mha = tf.keras.layers.MultiHeadAttention(num_heads=num_heads, key_dim=d_model // num_heads)
73
+ self.dropout1 = tf.keras.layers.Dropout(dropout_rate)
74
+ self.adapter_down = tf.keras.layers.Dense(adapter_dim, activation='gelu')
75
+ self.adapter_up = tf.keras.layers.Dense(d_model)
76
+
77
+ self.ln2 = tf.keras.layers.LayerNormalization(epsilon=1e-5)
78
+ self.ffn = SwiGLU(d_model, d_ff)
79
+ self.dropout2 = tf.keras.layers.Dropout(dropout_rate)
80
+ self.rope = RotaryPositionalEmbedding(d_model // num_heads)
81
+
82
+ def call(self, x, training=False):
83
+ x_norm = self.ln1(x)
84
+ b, s, _ = tf.shape(x_norm)[0], tf.shape(x_norm)[1], tf.shape(x_norm)[2]
85
+ h = self.mha.num_heads
86
+ d = x_norm.shape[-1] // h
87
+
88
+ qkv = tf.reshape(x_norm, [b, s, h, d])
89
+ qkv = tf.transpose(qkv, [0, 2, 1, 3])
90
+ q = self.rope(qkv)
91
+ k = self.rope(qkv)
92
+ q = tf.reshape(tf.transpose(q, [0, 2, 1, 3]), [b, s, h * d])
93
+ k = tf.reshape(tf.transpose(k, [0, 2, 1, 3]), [b, s, h * d])
94
+
95
+ attn_out = self.mha(query=q, value=x_norm, key=k, use_causal_mask=True, training=training)
96
+ attn_out = self.dropout1(attn_out, training=training)
97
+
98
+ adapter_out = self.adapter_up(self.adapter_down(attn_out))
99
+ attn_out = attn_out + adapter_out
100
+
101
+ x = x + attn_out
102
+ ffn_out = self.ffn(self.ln2(x))
103
+ x = x + self.dropout2(ffn_out, training=training)
104
+ return x
105
+
106
+ class InteractGPT(tf.keras.Model):
107
+ def __init__(self, vocab_size, seq_len, d_model, d_ff, n_layers, num_heads=8, dropout_rate=0.1):
108
+ super().__init__()
109
+ self.token_embedding = tf.keras.layers.Embedding(vocab_size, d_model)
110
+ self.blocks = [GPTBlock(d_model, d_ff, num_heads, dropout_rate) for _ in range(n_layers)]
111
+ self.ln_f = tf.keras.layers.LayerNormalization(epsilon=1e-5)
112
+
113
+ def call(self, x, training=False):
114
+ x = self.token_embedding(x)
115
+ for block in self.blocks:
116
+ x = block(x, training=training)
117
+ x = self.ln_f(x)
118
+ logits = tf.matmul(x, self.token_embedding.embeddings, transpose_b=True)
119
+ return logits
120
+
121
+ model = InteractGPT(vocab_size=vocab_size, seq_len=max_len, d_model=256, d_ff=1024, n_layers=6)
122
+
123
+ dummy_input = tf.zeros((1, max_len), dtype=tf.int32) # 배치1, 시퀀스길이 max_len
124
+ _ = model(dummy_input) # 모델이 빌드됨
125
+ model.load_weights("InteractGPT.weights.h5")
126
+ print("모델 가중치 로드 완료!")
127
+
128
+ def generate_text_mirostat_top_p(model, prompt, max_len=100, max_gen=98,
129
  temperature=1.0, min_len=20,
130
+ repetition_penalty=1.2, eta=0.1, m=100, p=0.9):
131
  model_input = text_to_ids(f"<start> {prompt} <sep>")
132
  model_input = model_input[:max_len]
133
  generated = list(model_input)
134
 
135
  tau = 5.0 # 초기 목표 surprise
 
136
 
137
  for step in range(max_gen):
138
  pad_length = max(0, max_len - len(generated))
 
148
  for token_id, count in token_counts.items():
149
  next_token_logits[token_id] /= (repetition_penalty ** count)
150
 
151
+ # 최소 길이 넘으면 종료 토큰 확률 낮추기
152
  if len(generated) >= min_len:
153
  next_token_logits[end_id] -= 5.0
154
  next_token_logits[pad_id] -= 10.0
155
 
156
+ # 온도 조절
157
  next_token_logits = next_token_logits / temperature
158
 
159
+ # --- 미로스타트 + Top-p 샘플링 ---
160
  logits_stable = next_token_logits - np.max(next_token_logits)
161
  probs = np.exp(logits_stable)
162
  probs /= probs.sum()
163
 
164
+ # 1. mirostat top-m 후보 추리기
165
  sorted_indices = np.argsort(-probs)
166
  top_indices = sorted_indices[:m]
167
  top_probs = probs[top_indices]
168
  top_probs /= top_probs.sum()
169
 
170
+ # 2. mirostat 샘플링
171
  sampled_index = np.random.choice(top_indices, p=top_probs)
172
  sampled_prob = probs[sampled_index]
173
  observed_surprise = -np.log(sampled_prob + 1e-9)
174
  tau += eta * (observed_surprise - tau)
175
 
176
+ # 3. top-p 필터링
177
  sorted_top_indices = top_indices[np.argsort(-top_probs)]
178
  sorted_top_probs = np.sort(top_probs)[::-1]
179
  cumulative_probs = np.cumsum(sorted_top_probs)
 
182
  filtered_probs = sorted_top_probs[:cutoff]
183
  filtered_probs /= filtered_probs.sum()
184
 
185
+ # 4. 최종 토큰 샘플링
186
  final_token = np.random.choice(filtered_indices, p=filtered_probs)
187
+ generated.append(int(final_token))
188
 
189
+ decoded_text = sp.decode(generated)
190
+ # 특수 토큰 제거
191
+ for token in ["<start>", "<sep>", "<end>"]:
192
+ decoded_text = decoded_text.replace(token, "")
 
 
 
 
193
 
194
+ decoded_text = decoded_text.strip()
 
195
 
196
+ if len(generated) >= min_len and (final_token == end_id or decoded_text.endswith(('.', '!', '?'))):
197
+ yield decoded_text
198
+ break
199
+
200
+ async def async_generator_wrapper(prompt: str):
201
+ # 동기 제너레이터를 비동기로 감싸기
202
+ loop = asyncio.get_event_loop()
203
+ gen = generate_text_mirostat_top_p(model, prompt)
204
+
205
+ for text_piece in gen:
206
+ yield text_piece
207
+ # 토큰 생성 속도 조절 (0.1초 딜레이)
208
+ await asyncio.sleep(0.1)
209
+
210
+ @app.get("/generate")
211
+ async def generate(request: Request):
212
+ # 쿼리 파라미터로 prompt 받음, 없으면 기본값
213
+ prompt = request.query_params.get("prompt", "안녕하세요")
214
 
215
+ # 스트리밍 응답으로 보냄
216
+ return StreamingResponse(async_generator_wrapper(prompt), media_type="text/plain")