psaiops 0.0.10__py3-none-any.whl → 0.0.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of psaiops might be problematic. Click here for more details.
psaiops/score/attention/app.py
CHANGED
|
@@ -24,16 +24,16 @@ def create_color_map() -> dict:
|
|
|
24
24
|
# INTRO ########################################################################
|
|
25
25
|
|
|
26
26
|
def create_intro_block(intro: str) -> dict:
|
|
27
|
-
__intro = gradio.Markdown(intro)
|
|
27
|
+
__intro = gradio.Markdown(intro, scale=1)
|
|
28
28
|
return {'intro_block': __intro}
|
|
29
29
|
|
|
30
30
|
# MODEL ########################################################################
|
|
31
31
|
|
|
32
32
|
def create_model_block() -> dict:
|
|
33
|
-
__model_dd = gradio.Dropdown(label='Model', value='openai/gpt-oss-20b', choices=['openai/gpt-oss-20b'], allow_custom_value=False, multiselect=False, interactive=True) # 'openai/gpt-oss-120b'
|
|
34
|
-
__layer_sl = gradio.Slider(label='Layer Depth', value=12, minimum=-1, maximum=23, step=1, interactive=True) # info='-1 to average on all layers'
|
|
35
|
-
__head_sl = gradio.Slider(label='Attention Head', value=-1, minimum=-1, maximum=63, step=1, interactive=True) # info='-1 to average on all heads'
|
|
36
|
-
__model_dd.change(fn=update_layer_range, inputs=[__layer_sl, __model_dd], outputs=__layer_sl, queue=False, show_progress='hidden')
|
|
33
|
+
__model_dd = gradio.Dropdown(label='Model', value='openai/gpt-oss-20b', choices=['openai/gpt-oss-20b'], scale=1, allow_custom_value=False, multiselect=False, interactive=True) # 'openai/gpt-oss-120b'
|
|
34
|
+
__layer_sl = gradio.Slider(label='Layer Depth', value=12, minimum=-1, maximum=23, step=1, scale=1, interactive=True) # info='-1 to average on all layers'
|
|
35
|
+
__head_sl = gradio.Slider(label='Attention Head', value=-1, minimum=-1, maximum=63, step=1, scale=1, interactive=True) # info='-1 to average on all heads'
|
|
36
|
+
__model_dd.change(fn=update_layer_range, inputs=[__layer_sl, __model_dd], outputs=__layer_sl, scale=1, queue=False, show_progress='hidden')
|
|
37
37
|
return {
|
|
38
38
|
'model_block': __model_dd,
|
|
39
39
|
'layer_block': __layer_sl,
|
|
@@ -42,37 +42,43 @@ def create_model_block() -> dict:
|
|
|
42
42
|
# SAMPLING #####################################################################
|
|
43
43
|
|
|
44
44
|
def create_sampling_block() -> dict:
|
|
45
|
-
__tokens = gradio.Slider(label='Tokens', value=
|
|
46
|
-
__topk = gradio.Slider(label='Top K', value=4, minimum=1, maximum=8, step=1, interactive=True)
|
|
47
|
-
__topp = gradio.Slider(label='Top P', value=0.
|
|
45
|
+
__tokens = gradio.Slider(label='Tokens', value=16, minimum=1, maximum=128, step=1, scale=1, interactive=True)
|
|
46
|
+
__topk = gradio.Slider(label='Top K', value=4, minimum=1, maximum=8, step=1, scale=1, interactive=True)
|
|
47
|
+
__topp = gradio.Slider(label='Top P', value=0.9, minimum=0.0, maximum=1.0, step=0.1, scale=1, interactive=True)
|
|
48
48
|
return {
|
|
49
49
|
'tokens_block': __tokens,
|
|
50
50
|
'topk_block': __topk,
|
|
51
51
|
'topp_block': __topp}
|
|
52
52
|
|
|
53
|
+
# TARGET #######################################################################
|
|
54
|
+
|
|
55
|
+
def create_target_block() -> dict:
|
|
56
|
+
__target = gradio.Radio(label='Score', value='Inputs', choices=['Inputs', 'Outputs', 'Both'], scale=1, interactive=True)
|
|
57
|
+
return {'target_block': __target}
|
|
58
|
+
|
|
53
59
|
# DISPLAY ######################################################################
|
|
54
60
|
|
|
55
61
|
def create_display_block() -> dict:
|
|
56
|
-
__display = gradio.Radio(label='Display', value='Tokens', choices=['Tokens', 'Indexes'], interactive=True)
|
|
62
|
+
__display = gradio.Radio(label='Display', value='Tokens', choices=['Tokens', 'Indexes'], scale=1, interactive=True)
|
|
57
63
|
return {'display_block': __display}
|
|
58
64
|
|
|
59
65
|
# INPUTS #######################################################################
|
|
60
66
|
|
|
61
67
|
def create_inputs_block() -> dict:
|
|
62
|
-
__input = gradio.Textbox(label='Prompt', value='', placeholder='A string of tokens to score.', lines=4, show_copy_button=True, interactive=True)
|
|
68
|
+
__input = gradio.Textbox(label='Prompt', value='', placeholder='A string of tokens to score.', lines=4, scale=1, show_copy_button=True, interactive=True)
|
|
63
69
|
return {'input_block': __input}
|
|
64
70
|
|
|
65
71
|
# OUTPUTS ######################################################################
|
|
66
72
|
|
|
67
73
|
def create_outputs_block() -> dict:
|
|
68
|
-
__output = gradio.HighlightedText(label='Scores', value='', interactive=False, show_legend=False, show_inline_category=False, combine_adjacent=True, color_map=create_color_map(), elem_classes='white-text')
|
|
74
|
+
__output = gradio.HighlightedText(label='Scores', value='', scale=1, interactive=False, show_legend=False, show_inline_category=False, combine_adjacent=True, color_map=create_color_map(), elem_classes='white-text')
|
|
69
75
|
return {'output_block': __output}
|
|
70
76
|
|
|
71
77
|
# ACTIONS ######################################################################
|
|
72
78
|
|
|
73
79
|
def create_actions_block() -> dict:
|
|
74
|
-
__process = gradio.Button('Process', variant='primary', size='lg', interactive=True)
|
|
75
|
-
__position = gradio.Slider(label='Position', value=-1, minimum=-1, maximum=128, step=1, interactive=True) # info='-1 to average on all tokens'
|
|
80
|
+
__process = gradio.Button('Process', variant='primary', size='lg', scale=1, interactive=True)
|
|
81
|
+
__position = gradio.Slider(label='Position', value=-1, minimum=-1, maximum=128, step=1, scale=1, interactive=True) # info='-1 to average on all tokens'
|
|
76
82
|
return {
|
|
77
83
|
'process_block': __process,
|
|
78
84
|
'position_block': __position}
|
|
@@ -80,7 +86,10 @@ def create_actions_block() -> dict:
|
|
|
80
86
|
# STATE ########################################################################
|
|
81
87
|
|
|
82
88
|
def create_state() -> dict:
|
|
83
|
-
return {
|
|
89
|
+
return {
|
|
90
|
+
'input_state': gradio.State(None),
|
|
91
|
+
'output_state': gradio.State(None),
|
|
92
|
+
'attention_state': gradio.State(None),}
|
|
84
93
|
|
|
85
94
|
# LAYOUT #######################################################################
|
|
86
95
|
|
|
@@ -90,36 +99,121 @@ def create_layout(intro: str=INTRO) -> dict:
|
|
|
90
99
|
with gradio.Tabs():
|
|
91
100
|
with gradio.Tab('Score Tokens') as __main_tab:
|
|
92
101
|
__fields.update({'main_tab': __main_tab})
|
|
93
|
-
with gradio.Row():
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
__fields.update(create_outputs_block())
|
|
98
|
-
with gradio.Row():
|
|
102
|
+
with gradio.Row(equal_height=True):
|
|
103
|
+
__fields.update(create_inputs_block())
|
|
104
|
+
__fields.update(create_outputs_block())
|
|
105
|
+
with gradio.Row(equal_height=True):
|
|
99
106
|
__fields.update(create_actions_block())
|
|
100
107
|
with gradio.Tab('Settings') as __settings_tab:
|
|
101
108
|
__fields.update({'settings_tab': __settings_tab})
|
|
102
109
|
with gradio.Column(scale=1):
|
|
103
|
-
with gradio.Row():
|
|
110
|
+
with gradio.Row(equal_height=True):
|
|
104
111
|
__fields.update(create_model_block())
|
|
105
|
-
with gradio.Row():
|
|
112
|
+
with gradio.Row(equal_height=True):
|
|
106
113
|
__fields.update(create_sampling_block())
|
|
107
|
-
with gradio.Row():
|
|
114
|
+
with gradio.Row(equal_height=True):
|
|
115
|
+
__fields.update(create_target_block())
|
|
108
116
|
__fields.update(create_display_block())
|
|
109
117
|
return __fields
|
|
110
118
|
|
|
111
119
|
# EVENTS #######################################################################
|
|
112
120
|
|
|
113
|
-
def update_layer_range(value:
|
|
121
|
+
def update_layer_range(value: float, model: str) -> dict:
|
|
114
122
|
return gradio.update(maximum=35, value=min(35, int(value))) if '120b' in model else gradio.update(maximum=23, value=min(23, int(value)))
|
|
115
123
|
|
|
116
|
-
def update_position_range(value:
|
|
117
|
-
return gradio.update(maximum=
|
|
118
|
-
|
|
119
|
-
def
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
124
|
+
def update_position_range(value: float, tokens: list) -> dict:
|
|
125
|
+
return gradio.update(maximum=len(tokens) - 1, value=min(len(tokens) - 1, int(value)))
|
|
126
|
+
|
|
127
|
+
def update_computation_state(
|
|
128
|
+
token_num: float,
|
|
129
|
+
topk_num: float,
|
|
130
|
+
topp_num: float,
|
|
131
|
+
prompt_str: str,
|
|
132
|
+
device_str: str,
|
|
133
|
+
model_obj: object,
|
|
134
|
+
tokenizer_obj: object,
|
|
135
|
+
) -> tuple:
|
|
136
|
+
# sanitize the inputs
|
|
137
|
+
__limit = max(1, min(128, int(token_num)))
|
|
138
|
+
__topk = max(1, min(128, int(token_num)))
|
|
139
|
+
__topp = max(0.0, min(1.0, float(token_num)))
|
|
140
|
+
__prompt = prompt_str.strip()
|
|
141
|
+
__device = device_str if (device_str in ['cpu', 'cuda']) else 'cpu'
|
|
142
|
+
# handle all exceptions at once
|
|
143
|
+
try:
|
|
144
|
+
# dictionary {'input_ids': _, 'attention_mask': _}
|
|
145
|
+
__inputs = psaiops.score.attention.lib.preprocess_token_ids(
|
|
146
|
+
tokenizer_obj=tokenizer_obj,
|
|
147
|
+
prompt_str=__prompt,
|
|
148
|
+
device_str=__device)
|
|
149
|
+
# parse the inputs
|
|
150
|
+
__input_dim = int(__inputs['input_ids'].shape[-1])
|
|
151
|
+
# tensor (1, T)
|
|
152
|
+
__outputs = psaiops.score.attention.lib.generate_token_ids(
|
|
153
|
+
model_obj=model_obj,
|
|
154
|
+
input_args=__inputs,
|
|
155
|
+
token_num=__limit,
|
|
156
|
+
topk_num=__topk,
|
|
157
|
+
topp_num=__topp)
|
|
158
|
+
# tensor (L, S, H, T, T)
|
|
159
|
+
__attentions = psaiops.score.attention.lib.compute_attention_weights(
|
|
160
|
+
model_obj=model_obj,
|
|
161
|
+
token_obj=__outputs)
|
|
162
|
+
# detokenize the IDs
|
|
163
|
+
__tokens = psaiops.score.attention.lib.postprocess_token_ids(
|
|
164
|
+
tokenizer_obj=tokenizer_obj,
|
|
165
|
+
token_obj=__outputs)
|
|
166
|
+
# update each component => (input, output, attention) states
|
|
167
|
+
return (
|
|
168
|
+
gradio.update(value=__tokens[:__input_dim]),
|
|
169
|
+
gradio.update(value=__tokens[__input_dim:]),
|
|
170
|
+
gradio.update(value=__attentions),)
|
|
171
|
+
except:
|
|
172
|
+
raise Exception('Attention generation aborted with an error.')
|
|
173
|
+
finally:
|
|
174
|
+
return (gradio.update(), gradio.update(), gradio.update())
|
|
175
|
+
|
|
176
|
+
def update_text_highlight(
|
|
177
|
+
token_idx: float,
|
|
178
|
+
layer_idx: float,
|
|
179
|
+
head_idx: float,
|
|
180
|
+
input_data: list,
|
|
181
|
+
output_data: list,
|
|
182
|
+
attention_data: torch.Tensor,
|
|
183
|
+
) -> dict:
|
|
184
|
+
# sanitize the inputs
|
|
185
|
+
__input_data = input_data or []
|
|
186
|
+
__output_data = output_data or []
|
|
187
|
+
__attention_data = attention_data or torch.empty(0)
|
|
188
|
+
__input_dim = len(__input_data)
|
|
189
|
+
__token_idx = max(0, min(__input_dim, int(token_idx)))
|
|
190
|
+
__layer_idx = max(0, int(layer_idx))
|
|
191
|
+
__head_idx = max(0, int(head_idx))
|
|
192
|
+
# exit if the data has not yet been computed
|
|
193
|
+
if (not __input_data) or (not __output_data) or (attention_data is None) or (len(attention_data) == 0):
|
|
194
|
+
return gradio.update()
|
|
195
|
+
# handle all exceptions at once
|
|
196
|
+
try:
|
|
197
|
+
# concat input and output tokens
|
|
198
|
+
__tokens = __input_data + __output_data
|
|
199
|
+
# reduce the layer, sample, head and output token axes => tensor (T,)
|
|
200
|
+
__scores = psaiops.score.attention.lib.reduce_attention_weights(
|
|
201
|
+
attention_data=__attention_data,
|
|
202
|
+
token_idx=__token_idx,
|
|
203
|
+
layer_idx=__layer_idx,
|
|
204
|
+
head_idx=__head_idx,
|
|
205
|
+
input_dim=__input_dim)
|
|
206
|
+
# translate the scores into integer labels
|
|
207
|
+
__labels = psaiops.score.attention.lib.postprocess_attention_scores(
|
|
208
|
+
attention_data=__scores,
|
|
209
|
+
input_dim=__input_dim,
|
|
210
|
+
token_idx=__token_idx)
|
|
211
|
+
# update the component with [(token, label), ...]
|
|
212
|
+
return gradio.update(value=list(zip(__tokens, __labels)))
|
|
213
|
+
except:
|
|
214
|
+
raise Exception('Attention reduction aborted with an error.')
|
|
215
|
+
finally:
|
|
216
|
+
return gradio.update()
|
|
123
217
|
|
|
124
218
|
# APP ##########################################################################
|
|
125
219
|
|
|
@@ -130,21 +224,40 @@ def create_app(title: str=TITLE, intro: str=INTRO, style: str=STYLE, model: str=
|
|
|
130
224
|
__device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
|
131
225
|
__model = psaiops.score.attention.lib.get_model(name=model, device=__device)
|
|
132
226
|
__tokenizer = psaiops.score.attention.lib.get_tokenizer(name=model, device=__device)
|
|
133
|
-
# adapt the
|
|
134
|
-
|
|
227
|
+
# adapt the computing function
|
|
228
|
+
__compute = functools.partial(update_computation_state, model_obj=__model, tokenizer_obj=__tokenizer, device_str=__device)
|
|
135
229
|
# create the UI
|
|
136
230
|
__fields.update(create_layout(intro=intro))
|
|
137
231
|
# init the state
|
|
138
232
|
__fields.update(create_state())
|
|
139
233
|
# fetch the relevant fields
|
|
140
|
-
|
|
234
|
+
__button_block, __position_block, __output_block = (__fields['process_block'], __fields['position_block'], __fields['output_block'])
|
|
235
|
+
__output_state, __attention_state = (__fields['output_state'], __fields['attention_state'])
|
|
141
236
|
# wire the input fields
|
|
142
|
-
|
|
143
|
-
fn=
|
|
144
|
-
inputs=[__fields[__k] for __k in ['
|
|
145
|
-
outputs=__fields['
|
|
237
|
+
__button_block.click(
|
|
238
|
+
fn=__compute,
|
|
239
|
+
inputs=[__fields[__k] for __k in ['tokens_block', 'topk_block', 'topp_block', 'input_block']],
|
|
240
|
+
outputs=[__fields[__k] for __k in ['input_state', 'output_state', 'attention_state']],
|
|
146
241
|
queue=False,
|
|
147
242
|
show_progress='full')
|
|
243
|
+
__output_state.change(
|
|
244
|
+
fn=update_position_range,
|
|
245
|
+
inputs=[__position_block, __output],
|
|
246
|
+
outputs=__position_block,
|
|
247
|
+
queue=False,
|
|
248
|
+
show_progress='hidden')
|
|
249
|
+
__attention_state.change(
|
|
250
|
+
fn=update_text_highlight,
|
|
251
|
+
inputs=[__fields[__k] for __k in ['position_block', 'layer_block', 'head_block', 'input_state', 'output_state', 'attention_state']],
|
|
252
|
+
outputs=__output_block,
|
|
253
|
+
queue=False,
|
|
254
|
+
show_progress='hidden')
|
|
255
|
+
__position_block.change(
|
|
256
|
+
fn=update_text_highlight,
|
|
257
|
+
inputs=[__fields[__k] for __k in ['position_block', 'layer_block', 'head_block', 'input_state', 'output_state', 'attention_state']],
|
|
258
|
+
outputs=__output_block,
|
|
259
|
+
queue=False,
|
|
260
|
+
show_progress='hidden')
|
|
148
261
|
# gradio application
|
|
149
262
|
return __app
|
|
150
263
|
|
psaiops/score/attention/lib.py
CHANGED
|
@@ -28,6 +28,7 @@ def get_model(name: str, device: str='cpu'):
|
|
|
28
28
|
|
|
29
29
|
# PREPROCESS #####################################################################
|
|
30
30
|
|
|
31
|
+
@functools.lru_cache(maxsize=4)
|
|
31
32
|
def preprocess_token_ids(
|
|
32
33
|
tokenizer_obj: object,
|
|
33
34
|
prompt_str: str,
|
|
@@ -137,7 +138,7 @@ def postprocess_token_ids(
|
|
|
137
138
|
# back to token strings
|
|
138
139
|
__tokens = tokenizer_obj.convert_ids_to_tokens(__indices)
|
|
139
140
|
# normalize the tokens
|
|
140
|
-
return [__t.replace('
|
|
141
|
+
return [__t.replace(chr(0x0120), ' ').replace(chr(0x010a), '\n') for __t in __tokens]
|
|
141
142
|
|
|
142
143
|
# COMPUTE ########################################################################
|
|
143
144
|
|
|
@@ -149,7 +150,6 @@ def score_tokens(
|
|
|
149
150
|
token_idx: int,
|
|
150
151
|
layer_idx: int,
|
|
151
152
|
head_idx: int,
|
|
152
|
-
*,
|
|
153
153
|
device_str: str,
|
|
154
154
|
model_obj: object,
|
|
155
155
|
tokenizer_obj: object,
|
|
@@ -7,9 +7,9 @@ psaiops/elements/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
|
7
7
|
psaiops/elements/data.py,sha256=vGYeMN11uP9gs8rV6aSDffE_TeIX5PmdzWGwUpdGE2Y,906
|
|
8
8
|
psaiops/score/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
9
|
psaiops/score/attention/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
psaiops/score/attention/app.py,sha256=
|
|
11
|
-
psaiops/score/attention/lib.py,sha256=
|
|
10
|
+
psaiops/score/attention/app.py,sha256=SS-cQ45HAv03rxGjzRNCV5BIfyP_Qry58bJ0b3OIxZU,11979
|
|
11
|
+
psaiops/score/attention/lib.py,sha256=kPLdmWCYbpMnd7fi4ZeCvxiGzJuvTKYSXgRAm_w02KA,6928
|
|
12
12
|
psaiops/steer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
|
-
psaiops-0.0.
|
|
14
|
-
psaiops-0.0.
|
|
15
|
-
psaiops-0.0.
|
|
13
|
+
psaiops-0.0.11.dist-info/METADATA,sha256=s3jjhNDNG0Zm-pBoxrkuznmkuxJr-04Dxj6MbFsCNIA,1222
|
|
14
|
+
psaiops-0.0.11.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
|
|
15
|
+
psaiops-0.0.11.dist-info/RECORD,,
|
|
File without changes
|