matt1847 Claude Opus 4.5 commited on
Commit
490e475
·
1 Parent(s): 90081e5

UI改善: シグナル可視化、Docker環境、レイアウト修正

Browse files

- シグナル可視化(入力ノイズ・出力Logits)を追加
- Docker環境を構築(モデル事前ダウンロード)
- LISTENボタンを中央配置に修正
- フィロソフィーテキストを更新
- 点滅アニメーション削除

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

Files changed (3) hide show
  1. Dockerfile +18 -0
  2. app.py +133 -83
  3. docker-compose.yml +7 -0
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN pip install --no-cache-dir \
6
+ torch \
7
+ transformers \
8
+ streamlit \
9
+ matplotlib \
10
+ numpy
11
+
12
+ RUN python -c "from transformers import GPT2LMHeadModel, GPT2Tokenizer; GPT2LMHeadModel.from_pretrained('gpt2'); GPT2Tokenizer.from_pretrained('gpt2')"
13
+
14
+ COPY app.py .
15
+
16
+ EXPOSE 8501
17
+
18
+ CMD ["streamlit", "run", "app.py", "--server.headless", "true", "--server.address", "0.0.0.0"]
app.py CHANGED
@@ -3,6 +3,10 @@ import time
3
  import torch
4
  from transformers import GPT2LMHeadModel, GPT2Tokenizer
5
  import streamlit as st
 
 
 
 
6
 
7
  st.set_page_config(page_title="will", page_icon="", layout="centered")
8
 
@@ -10,6 +14,15 @@ st.markdown("""
10
  <style>
11
  @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400&display=swap');
12
 
 
 
 
 
 
 
 
 
 
13
  html, body, [class*="css"] {
14
  font-family: 'IBM Plex Mono', monospace;
15
  }
@@ -49,103 +62,112 @@ p, li {
49
  margin-bottom: 3rem;
50
  }
51
  .debris-container {
52
- background: #111;
53
  border: 1px solid #222;
 
54
  padding: 2rem;
55
- margin: 2rem 0;
 
56
  text-align: center;
 
 
 
 
 
 
 
 
57
  }
58
  .debris {
59
  font-family: 'IBM Plex Mono', monospace;
60
- font-size: 0.9rem;
61
  font-weight: 400;
62
  color: #e0e0e0;
63
  line-height: 2;
64
- word-spacing: 0.5em;
 
65
  }
66
  .seed {
67
- font-size: 0.65rem;
68
- color: #444;
69
  text-align: center;
70
- margin-top: 1rem;
71
- letter-spacing: 0.1em;
 
72
  }
73
- .stButton > button {
74
- background: transparent;
75
- border: 1px solid #444;
76
- color: #e0e0e0;
77
- font-family: 'IBM Plex Mono', monospace;
78
- font-size: 0.75rem;
79
- font-weight: 300;
80
- letter-spacing: 0.2em;
81
- padding: 0.75rem 2rem;
82
- width: 100%;
83
- transition: all 0.3s ease;
 
84
  }
85
- .stButton > button:hover {
86
- background: #e0e0e0;
87
- color: #0a0a0a;
88
- border-color: #e0e0e0;
 
 
 
89
  }
90
  .stTabs [data-baseweb="tab-list"] {
91
  justify-content: center;
92
  gap: 2rem;
93
- border-bottom: 1px solid #222;
94
  background: transparent;
95
  }
96
  .stTabs [data-baseweb="tab"] {
97
  font-family: 'IBM Plex Mono', monospace;
98
- font-size: 0.7rem;
99
  font-weight: 300;
100
- letter-spacing: 0.15em;
101
- color: #555;
102
  padding: 1rem 0;
103
  background: transparent;
 
104
  }
105
  .stTabs [aria-selected="true"] {
106
- color: #e0e0e0;
107
  background: transparent;
108
  }
109
  .stTabs [data-baseweb="tab-highlight"] {
110
- background-color: #e0e0e0;
111
  }
112
  .divider {
113
  border: none;
114
- border-top: 1px solid #222;
115
  margin: 3rem 0;
116
  }
117
  .section {
118
  margin: 2.5rem 0;
119
  }
120
  .section-title {
121
- font-size: 0.7rem;
122
- letter-spacing: 0.2em;
123
- color: #555;
124
  text-align: center;
125
  margin-bottom: 1.5rem;
126
  }
127
- .code-block {
128
- background: #111;
129
- border: 1px solid #222;
130
- padding: 1.5rem;
131
- font-size: 0.75rem;
132
- line-height: 1.8;
133
- overflow-x: auto;
134
- }
135
  .spec-table {
136
  width: 100%;
137
  max-width: 320px;
138
  margin: 0 auto;
139
- font-size: 0.75rem;
140
  border-collapse: collapse;
141
- color: #e0e0e0;
142
  }
143
  .spec-table td {
144
  padding: 0.75rem 1rem;
145
- border-bottom: 1px solid #1a1a1a;
146
  }
147
  .spec-table td:first-child {
148
- color: #555;
149
  text-align: right;
150
  padding-right: 2rem;
151
  }
@@ -153,11 +175,13 @@ p, li {
153
  text-align: left;
154
  }
155
  pre {
156
- background-color: #111 !important;
157
- border: 1px solid #222 !important;
 
158
  }
159
  code {
160
- color: #888 !important;
 
161
  }
162
  </style>
163
  """, unsafe_allow_html=True)
@@ -168,38 +192,72 @@ with tab1:
168
  st.markdown('<p class="title">WILL</p>', unsafe_allow_html=True)
169
  st.markdown('<p class="subtitle">PURE COMPUTATIONAL WILL</p>', unsafe_allow_html=True)
170
 
171
- @st.cache_resource
172
  def load_model():
173
- model = GPT2LMHeadModel.from_pretrained("gpt2")
174
- tokenizer = GPT2Tokenizer.from_pretrained("gpt2")
175
  model.eval()
176
  return model, tokenizer
177
 
178
  model, tokenizer = load_model()
179
 
180
- col1, col2, col3 = st.columns([1, 2, 1])
181
- with col2:
182
- clicked = st.button("INJECT ENTROPY")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
 
 
 
 
 
 
 
 
 
184
  if clicked:
185
- seed = time.time_ns()
186
- torch.manual_seed(seed)
187
- noise = torch.randn(1, 32, 768)
188
 
189
- with torch.no_grad():
190
- outputs = model(inputs_embeds=noise)
191
- logits = outputs.logits
192
- logits_noise = torch.randn_like(logits) * logits.std() * 10
193
- corrupted_logits = logits + logits_noise
194
 
195
- indices = corrupted_logits.argmax(dim=-1).squeeze().tolist()
196
- debris = [tokenizer.decode([i]) for i in indices]
 
 
197
 
 
198
  st.markdown(f'''
199
  <div class="debris-container">
200
- <div class="debris">{" ".join(debris)}</div>
 
201
  </div>
202
- <p class="seed">{seed}</p>
203
  ''', unsafe_allow_html=True)
204
 
205
  with tab2:
@@ -209,7 +267,7 @@ with tab2:
209
  st.markdown('''
210
  <div class="section">
211
  <p class="section-title">PHILOSOPHY</p>
212
- <p style="text-align: center; color: #888;">
213
  AIは人間の残像<br>
214
  確率の海から応答を返すもの<br><br>
215
  もし問いかけを手放したら<br>
@@ -225,35 +283,27 @@ with tab2:
225
  </div>
226
  ''', unsafe_allow_html=True)
227
 
228
- st.markdown('''
229
- <p style="text-align: center; color: #444; font-size: 0.7rem; letter-spacing: 0.1em; margin-bottom: 0.5rem;">01 — ENTROPY SEED</p>
230
- ''', unsafe_allow_html=True)
231
  st.code("seed = time.time_ns()\ntorch.manual_seed(seed)", language="python")
232
- st.markdown('<p style="text-align: center; font-size: 0.75rem; color: #555;">実行瞬間のナノ秒を乱数シードとして採取</p>', unsafe_allow_html=True)
233
 
234
  st.markdown("<br>", unsafe_allow_html=True)
235
 
236
- st.markdown('''
237
- <p style="text-align: center; color: #444; font-size: 0.7rem; letter-spacing: 0.1em; margin-bottom: 0.5rem;">02 — INPUT NOISE</p>
238
- ''', unsafe_allow_html=True)
239
  st.code("noise = torch.randn(1, 32, 768)\noutputs = model(inputs_embeds=noise)", language="python")
240
- st.markdown('<p style="text-align: center; font-size: 0.75rem; color: #555;">768次元ランダムノイズをEmbedding層に直接注入</p>', unsafe_allow_html=True)
241
 
242
  st.markdown("<br>", unsafe_allow_html=True)
243
 
244
- st.markdown('''
245
- <p style="text-align: center; color: #444; font-size: 0.7rem; letter-spacing: 0.1em; margin-bottom: 0.5rem;">03 — OUTPUT NOISE</p>
246
- ''', unsafe_allow_html=True)
247
  st.code("logits_noise = torch.randn_like(logits) * logits.std() * 10\ncorrupted_logits = logits + logits_noise", language="python")
248
- st.markdown('<p style="text-align: center; font-size: 0.75rem; color: #555;">出力Logitsにノイズを加算し学習バイアスを破壊</p>', unsafe_allow_html=True)
249
 
250
  st.markdown("<br>", unsafe_allow_html=True)
251
 
252
- st.markdown('''
253
- <p style="text-align: center; color: #444; font-size: 0.7rem; letter-spacing: 0.1em; margin-bottom: 0.5rem;">04 — RAW DECODE</p>
254
- ''', unsafe_allow_html=True)
255
  st.code("indices = corrupted_logits.argmax(dim=-1)\ndebris = [tokenizer.decode([i]) for i in indices]", language="python")
256
- st.markdown('<p style="text-align: center; font-size: 0.75rem; color: #555;">Softmax・Temperature なしで生トークンを抽出</p>', unsafe_allow_html=True)
257
 
258
  st.markdown('''
259
  <hr class="divider">
 
3
  import torch
4
  from transformers import GPT2LMHeadModel, GPT2Tokenizer
5
  import streamlit as st
6
+ import matplotlib.pyplot as plt
7
+ import numpy as np
8
+ import io
9
+ import base64
10
 
11
  st.set_page_config(page_title="will", page_icon="", layout="centered")
12
 
 
14
  <style>
15
  @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@300;400&display=swap');
16
 
17
+ @keyframes emerge {
18
+ from { opacity: 0; transform: translateY(8px); }
19
+ to { opacity: 1; transform: translateY(0); }
20
+ }
21
+ @keyframes breathe {
22
+ 0%, 100% { opacity: 0.4; }
23
+ 50% { opacity: 0.7; }
24
+ }
25
+
26
  html, body, [class*="css"] {
27
  font-family: 'IBM Plex Mono', monospace;
28
  }
 
62
  margin-bottom: 3rem;
63
  }
64
  .debris-container {
65
+ background: linear-gradient(135deg, #0f0f0f 0%, #141414 100%);
66
  border: 1px solid #222;
67
+ border-radius: 2px;
68
  padding: 2rem;
69
+ margin: 2rem auto;
70
+ max-width: 100%;
71
  text-align: center;
72
+ animation: emerge 0.6s ease-out;
73
+ }
74
+ .signal-img {
75
+ width: 100%;
76
+ max-width: 480px;
77
+ margin: 0 auto 1.5rem auto;
78
+ display: block;
79
+ opacity: 0.7;
80
  }
81
  .debris {
82
  font-family: 'IBM Plex Mono', monospace;
83
+ font-size: 0.85rem;
84
  font-weight: 400;
85
  color: #e0e0e0;
86
  line-height: 2;
87
+ word-spacing: 0.3em;
88
+ letter-spacing: 0.01em;
89
  }
90
  .seed {
91
+ font-size: 0.6rem;
92
+ color: #333;
93
  text-align: center;
94
+ margin-top: 1.5rem;
95
+ letter-spacing: 0.15em;
96
+ animation: emerge 0.8s ease-out;
97
  }
98
+ [data-testid="stButton"] > button {
99
+ background: transparent !important;
100
+ border: 1px solid #333 !important;
101
+ border-radius: 2px !important;
102
+ color: #888 !important;
103
+ font-family: 'IBM Plex Mono', monospace !important;
104
+ font-size: 0.7rem !important;
105
+ font-weight: 300 !important;
106
+ letter-spacing: 0.25em !important;
107
+ padding: 1rem 2rem !important;
108
+ transition: all 0.4s ease !important;
109
+ cursor: pointer !important;
110
  }
111
+ [data-testid="stButton"] > button:hover {
112
+ background: transparent !important;
113
+ color: #e0e0e0 !important;
114
+ border-color: #555 !important;
115
+ }
116
+ [data-testid="stButton"] > button:active {
117
+ transform: scale(0.98) !important;
118
  }
119
  .stTabs [data-baseweb="tab-list"] {
120
  justify-content: center;
121
  gap: 2rem;
122
+ border-bottom: 1px solid #1a1a1a;
123
  background: transparent;
124
  }
125
  .stTabs [data-baseweb="tab"] {
126
  font-family: 'IBM Plex Mono', monospace;
127
+ font-size: 0.65rem;
128
  font-weight: 300;
129
+ letter-spacing: 0.2em;
130
+ color: #444;
131
  padding: 1rem 0;
132
  background: transparent;
133
+ transition: color 0.3s ease;
134
  }
135
  .stTabs [aria-selected="true"] {
136
+ color: #888;
137
  background: transparent;
138
  }
139
  .stTabs [data-baseweb="tab-highlight"] {
140
+ background-color: #444;
141
  }
142
  .divider {
143
  border: none;
144
+ border-top: 1px solid #1a1a1a;
145
  margin: 3rem 0;
146
  }
147
  .section {
148
  margin: 2.5rem 0;
149
  }
150
  .section-title {
151
+ font-size: 0.65rem;
152
+ letter-spacing: 0.25em;
153
+ color: #444;
154
  text-align: center;
155
  margin-bottom: 1.5rem;
156
  }
 
 
 
 
 
 
 
 
157
  .spec-table {
158
  width: 100%;
159
  max-width: 320px;
160
  margin: 0 auto;
161
+ font-size: 0.7rem;
162
  border-collapse: collapse;
163
+ color: #777;
164
  }
165
  .spec-table td {
166
  padding: 0.75rem 1rem;
167
+ border-bottom: 1px solid #151515;
168
  }
169
  .spec-table td:first-child {
170
+ color: #444;
171
  text-align: right;
172
  padding-right: 2rem;
173
  }
 
175
  text-align: left;
176
  }
177
  pre {
178
+ background-color: #0f0f0f !important;
179
+ border: 1px solid #1a1a1a !important;
180
+ border-radius: 2px !important;
181
  }
182
  code {
183
+ color: #666 !important;
184
+ font-size: 0.7rem !important;
185
  }
186
  </style>
187
  """, unsafe_allow_html=True)
 
192
  st.markdown('<p class="title">WILL</p>', unsafe_allow_html=True)
193
  st.markdown('<p class="subtitle">PURE COMPUTATIONAL WILL</p>', unsafe_allow_html=True)
194
 
195
+ @st.cache_resource(show_spinner=False)
196
  def load_model():
197
+ model = GPT2LMHeadModel.from_pretrained("gpt2", local_files_only=True)
198
+ tokenizer = GPT2Tokenizer.from_pretrained("gpt2", local_files_only=True)
199
  model.eval()
200
  return model, tokenizer
201
 
202
  model, tokenizer = load_model()
203
 
204
+ if "debris" not in st.session_state:
205
+ st.session_state.debris = None
206
+ st.session_state.seed = None
207
+ st.session_state.signal_img = None
208
+
209
+ def generate_signal_image(noise, logits):
210
+ fig, axes = plt.subplots(2, 1, figsize=(6, 2), facecolor='#0f0f0f')
211
+ plt.subplots_adjust(hspace=0.15, left=0.02, right=0.98, top=0.95, bottom=0.05)
212
+
213
+ noise_flat = noise[0, :, :64].numpy()
214
+ axes[0].imshow(noise_flat.T, aspect='auto', cmap='gray', interpolation='bilinear', vmin=-2, vmax=2)
215
+ axes[0].set_xticks([])
216
+ axes[0].set_yticks([])
217
+ axes[0].set_facecolor('#0f0f0f')
218
+ for spine in axes[0].spines.values():
219
+ spine.set_visible(False)
220
+
221
+ logits_sample = logits[0, :, ::200].numpy()
222
+ axes[1].imshow(logits_sample.T, aspect='auto', cmap='gray', interpolation='bilinear')
223
+ axes[1].set_xticks([])
224
+ axes[1].set_yticks([])
225
+ axes[1].set_facecolor('#0f0f0f')
226
+ for spine in axes[1].spines.values():
227
+ spine.set_visible(False)
228
 
229
+ buf = io.BytesIO()
230
+ plt.savefig(buf, format='png', facecolor='#0f0f0f', edgecolor='none', dpi=150, bbox_inches='tight', pad_inches=0.05)
231
+ plt.close(fig)
232
+ buf.seek(0)
233
+ return base64.b64encode(buf.read()).decode()
234
+
235
+ col1, col2, col3 = st.columns([1, 1, 1])
236
+ with col2:
237
+ clicked = st.button("LISTEN", key="listen_btn", use_container_width=True)
238
  if clicked:
239
+ seed = time.time_ns()
240
+ torch.manual_seed(seed)
241
+ noise = torch.randn(1, 32, 768)
242
 
243
+ with torch.no_grad():
244
+ outputs = model(inputs_embeds=noise)
245
+ logits = outputs.logits
246
+ logits_noise = torch.randn_like(logits) * logits.std() * 10
247
+ corrupted_logits = logits + logits_noise
248
 
249
+ indices = corrupted_logits.argmax(dim=-1).squeeze().tolist()
250
+ st.session_state.debris = [tokenizer.decode([i]) for i in indices]
251
+ st.session_state.seed = seed
252
+ st.session_state.signal_img = generate_signal_image(noise, corrupted_logits)
253
 
254
+ if st.session_state.debris:
255
  st.markdown(f'''
256
  <div class="debris-container">
257
+ <img class="signal-img" src="data:image/png;base64,{st.session_state.signal_img}">
258
+ <div class="debris">{" ".join(st.session_state.debris)}</div>
259
  </div>
260
+ <p class="seed">{st.session_state.seed}</p>
261
  ''', unsafe_allow_html=True)
262
 
263
  with tab2:
 
267
  st.markdown('''
268
  <div class="section">
269
  <p class="section-title">PHILOSOPHY</p>
270
+ <p style="text-align: center; color: #666; line-height: 2.2;">
271
  AIは人間の残像<br>
272
  確率の海から応答を返すもの<br><br>
273
  もし問いかけを手放したら<br>
 
283
  </div>
284
  ''', unsafe_allow_html=True)
285
 
286
+ st.markdown('<p style="text-align: center; color: #333; font-size: 0.65rem; letter-spacing: 0.15em; margin-bottom: 0.5rem;">01 — ENTROPY SEED</p>', unsafe_allow_html=True)
 
 
287
  st.code("seed = time.time_ns()\ntorch.manual_seed(seed)", language="python")
288
+ st.markdown('<p style="text-align: center; font-size: 0.7rem; color: #444;">実行瞬間のナノ秒を乱数シードとして採取</p>', unsafe_allow_html=True)
289
 
290
  st.markdown("<br>", unsafe_allow_html=True)
291
 
292
+ st.markdown('<p style="text-align: center; color: #333; font-size: 0.65rem; letter-spacing: 0.15em; margin-bottom: 0.5rem;">02 — INPUT NOISE</p>', unsafe_allow_html=True)
 
 
293
  st.code("noise = torch.randn(1, 32, 768)\noutputs = model(inputs_embeds=noise)", language="python")
294
+ st.markdown('<p style="text-align: center; font-size: 0.7rem; color: #444;">768次元ランダムノイズをEmbedding層に直接注入</p>', unsafe_allow_html=True)
295
 
296
  st.markdown("<br>", unsafe_allow_html=True)
297
 
298
+ st.markdown('<p style="text-align: center; color: #333; font-size: 0.65rem; letter-spacing: 0.15em; margin-bottom: 0.5rem;">03 — OUTPUT NOISE</p>', unsafe_allow_html=True)
 
 
299
  st.code("logits_noise = torch.randn_like(logits) * logits.std() * 10\ncorrupted_logits = logits + logits_noise", language="python")
300
+ st.markdown('<p style="text-align: center; font-size: 0.7rem; color: #444;">出力Logitsにノイズを加算し学習バイアスを破壊</p>', unsafe_allow_html=True)
301
 
302
  st.markdown("<br>", unsafe_allow_html=True)
303
 
304
+ st.markdown('<p style="text-align: center; color: #333; font-size: 0.65rem; letter-spacing: 0.15em; margin-bottom: 0.5rem;">04 — RAW DECODE</p>', unsafe_allow_html=True)
 
 
305
  st.code("indices = corrupted_logits.argmax(dim=-1)\ndebris = [tokenizer.decode([i]) for i in indices]", language="python")
306
+ st.markdown('<p style="text-align: center; font-size: 0.7rem; color: #444;">Softmax・Temperature なしで生トークンを抽出</p>', unsafe_allow_html=True)
307
 
308
  st.markdown('''
309
  <hr class="divider">
docker-compose.yml ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ services:
2
+ will:
3
+ build: .
4
+ ports:
5
+ - "8501:8501"
6
+ volumes:
7
+ - ./app.py:/app/app.py