sillyguy21 commited on
Commit
086aeef
·
verified ·
1 Parent(s): 9fcfc2c

update model.py

Browse files
Files changed (1) hide show
  1. model.py +135 -46
model.py CHANGED
@@ -1,7 +1,9 @@
1
 
2
- """AlignDRAW — checkpoint-compatible 32x32 PyTorch implementation.
3
- Original architecture dimensions preserved.
4
- Default generation steps: 69.
 
 
5
  """
6
 
7
  import torch
@@ -10,10 +12,10 @@ import torch.nn.functional as F
10
 
11
 
12
  def _lstm(pre, cell, H):
13
- i = torch.sigmoid(pre[:, 0 * H:1 * H])
14
- f = torch.sigmoid(pre[:, 1 * H:2 * H])
15
- g = torch.tanh(pre[:, 2 * H:3 * H])
16
- o = torch.sigmoid(pre[:, 3 * H:4 * H])
17
  cell = f * cell + i * g
18
  return o * torch.tanh(cell), cell
19
 
@@ -31,35 +33,43 @@ class SelectiveAttention:
31
  return gx, gy, delta, sigma, gamma
32
 
33
  def _fb(self, g, delta, sigma, size):
34
- grid = torch.arange(self.N, device=g.device).float() - self.N // 2 - 0.5
 
 
 
35
  mu = g.unsqueeze(1) + delta.unsqueeze(1) * grid.unsqueeze(0)
36
- a = torch.arange(size, device=g.device).float()
 
37
  fb = torch.exp(
38
  -((a.view(1, 1, -1) - mu.unsqueeze(2)) ** 2)
39
  / (2 * sigma.view(-1, 1, 1) ** 2 + 1e-8)
40
  )
 
41
  return fb / (fb.sum(-1, keepdim=True) + 1e-4)
42
 
43
  def read(self, img, gx, gy, delta, sigma):
44
  Fx = self._fb(gx, delta, sigma, self.W)
45
  Fy = self._fb(gy, delta, sigma, self.H)
 
46
  t = torch.einsum('bnh,bchw->bcnw', Fy, img)
47
  return torch.einsum('bcnw,bmw->bcnm', t, Fx)
48
 
49
  def write(self, win, gx, gy, delta, sigma):
50
  Fx = self._fb(gx, delta, sigma, self.W)
51
  Fy = self._fb(gy, delta, sigma, self.H)
 
52
  t = torch.einsum('bnh,bcnm->bchm', Fy, win)
53
  return torch.einsum('bchm,bmw->bchw', t, Fx)
54
 
55
 
56
  class AlignDRAW(nn.Module):
 
57
  def __init__(
58
  self,
59
  dimY=25323,
60
  dimLangRNN=128,
61
  dimAlign=512,
62
- imgSize=32,
63
  dimReadAttent=9,
64
  dimWriteAttent=9,
65
  dimRNNEnc=550,
@@ -71,13 +81,14 @@ class AlignDRAW(nn.Module):
71
 
72
  self.C = 3
73
  self.H = self.W = imgSize
74
- self.dimX = self.C * imgSize * imgSize
75
 
76
  self.Nr, self.Nw = dimReadAttent, dimWriteAttent
77
- self.He, self.Hd, self.Z, self.T = dimRNNEnc, dimRNNDec, dimZ, runSteps
 
78
  self.Hl, self.Al = dimLangRNN, dimAlign
79
 
80
- # Language encoder
81
  self.emb_f = nn.Embedding(dimY, 4 * dimLangRNN)
82
  self.Wh_f = nn.Linear(dimLangRNN, 4 * dimLangRNN, bias=False)
83
  self.b_f = nn.Parameter(torch.zeros(4 * dimLangRNN))
@@ -86,42 +97,75 @@ class AlignDRAW(nn.Module):
86
  self.Wh_b = nn.Linear(dimLangRNN, 4 * dimLangRNN, bias=False)
87
  self.b_b = nn.Parameter(torch.zeros(4 * dimLangRNN))
88
 
89
- # Attention alignment
90
- self.W_lang_align = nn.Linear(2 * dimLangRNN, dimAlign, bias=False)
91
- self.W_hdec_align = nn.Linear(dimRNNDec, dimAlign, bias=False)
 
 
 
 
 
92
  self.b_align = nn.Parameter(torch.zeros(dimAlign))
93
  self.v_align = nn.Parameter(torch.randn(dimAlign) * 0.01)
94
- self.W_s_hdec = nn.Linear(2 * dimLangRNN, 4 * dimRNNDec, bias=False)
95
 
96
- # Reader and encoder
 
 
 
 
97
  self.W_read = nn.Linear(dimRNNDec, 5)
 
98
  read_dim = 2 * self.C * self.Nr * self.Nr
99
 
100
- self.Wh_enc = nn.Linear(dimRNNEnc, 4 * dimRNNEnc, bias=False)
101
- self.Wi_enc = nn.Linear(read_dim + dimRNNDec, 4 * dimRNNEnc, bias=False)
 
 
 
 
 
 
 
 
 
102
  self.b_enc = nn.Parameter(torch.zeros(4 * dimRNNEnc))
103
 
104
  self.W_mu = nn.Linear(dimRNNEnc, dimZ)
105
  self.W_logsigma = nn.Linear(dimRNNEnc, dimZ)
106
 
107
  # Decoder and learned prior
108
- self.Wh_dec = nn.Linear(dimRNNDec, 4 * dimRNNDec, bias=False)
109
- self.Wz_dec = nn.Linear(dimZ, 4 * dimRNNDec, bias=False)
 
 
 
 
 
 
110
  self.b_dec = nn.Parameter(torch.zeros(4 * dimRNNDec))
111
  self.W_prior = nn.Linear(dimRNNDec, 2 * dimZ)
112
 
113
- # Writer
114
  self.W_write = nn.Linear(dimRNNDec, 5)
115
- self.W_c = nn.Linear(dimRNNDec, self.C * self.Nw * self.Nw)
116
 
117
- # Original checkpoint-compatible initial states
 
 
 
 
118
  self.h0_lang = nn.Parameter(torch.zeros(1, dimLangRNN))
119
  self.h0_enc = nn.Parameter(torch.zeros(1, dimRNNEnc))
120
  self.h0_dec = nn.Parameter(torch.zeros(1, dimRNNDec))
 
121
  self.c0 = nn.Parameter(torch.zeros(1, self.dimX))
122
 
123
- self.reader = SelectiveAttention(self.H, self.W, self.Nr)
124
- self.writer = SelectiveAttention(self.H, self.W, self.Nw)
 
 
 
 
 
125
 
126
  self._init_weights()
127
 
@@ -129,6 +173,7 @@ class AlignDRAW(nn.Module):
129
  for m in self.modules():
130
  if isinstance(m, (nn.Linear, nn.Embedding)):
131
  nn.init.normal_(m.weight, 0.0, 0.01)
 
132
  if getattr(m, "bias", None) is not None:
133
  nn.init.zeros_(m.bias)
134
 
@@ -149,15 +194,20 @@ class AlignDRAW(nn.Module):
149
  self.emb_f(y[:, t]) + self.Wh_f(hf) + self.b_f,
150
  cf, self.Hl
151
  )
 
152
  hb, cb = _lstm(
153
  self.emb_b(yr[:, t]) + self.Wh_b(hb) + self.b_b,
154
  cb, self.Hl
155
  )
 
156
  outs_f.append(hf)
157
  outs_b.append(hb)
158
 
159
  hlang = torch.cat(
160
- [torch.stack(outs_f, 1), torch.stack(outs_b, 1)],
 
 
 
161
  dim=2
162
  )
163
 
@@ -165,16 +215,25 @@ class AlignDRAW(nn.Module):
165
 
166
  def _align(self, hlang, hid_align, h_dec):
167
  e = torch.tanh(
168
- hid_align + self.W_hdec_align(h_dec).unsqueeze(1) + self.b_align
 
 
169
  )
 
170
  e = (e * self.v_align).sum(-1)
171
  alpha = F.softmax(e, dim=1)
 
172
  s = (alpha.unsqueeze(2) * hlang).sum(1)
 
173
  return s, alpha
174
 
175
  def forward(self, x, y):
176
  b = x.shape[0]
177
 
 
 
 
 
178
  h_dec = self.h0_dec.expand(b, -1).contiguous()
179
  cell_dec = x.new_zeros(b, self.Hd)
180
 
@@ -187,21 +246,28 @@ class AlignDRAW(nn.Module):
187
  ls_p = x.new_zeros(b, self.Z)
188
 
189
  hlang, hid_align = self.encode_caption(y)
 
190
  ximg = x.view(b, self.C, self.H, self.W)
191
 
192
  kl = x.new_zeros(())
193
 
194
  for _ in range(self.T):
 
195
  x_hat = ximg - torch.sigmoid(c).view(
196
  b, self.C, self.H, self.W
197
  )
198
 
199
- gx, gy, dl, sg, gm = self.reader.params(self.W_read(h_dec))
 
 
200
 
201
- r = gm[:, :, None, None] * torch.cat([
202
- self.reader.read(ximg, gx, gy, dl, sg),
203
- self.reader.read(x_hat, gx, gy, dl, sg)
204
- ], dim=1)
 
 
 
205
 
206
  r = r.reshape(b, -1)
207
 
@@ -211,7 +277,8 @@ class AlignDRAW(nn.Module):
211
  self.Wh_enc(h_enc)
212
  + self.Wi_enc(torch.cat([r, h_dec], 1))
213
  + self.b_enc,
214
- cell_enc, self.He
 
215
  )
216
 
217
  mu = self.W_mu(h_enc)
@@ -221,8 +288,9 @@ class AlignDRAW(nn.Module):
221
 
222
  kl = kl + torch.sum(
223
  -1
224
- + ((mu - mu_p) ** 2 + torch.exp(2 * ls))
225
- / torch.exp(2 * ls_p)
 
226
  - 2 * ls + 2 * ls_p
227
  )
228
 
@@ -231,13 +299,18 @@ class AlignDRAW(nn.Module):
231
  + self.Wz_dec(z)
232
  + self.W_s_hdec(s)
233
  + self.b_dec,
234
- cell_dec, self.Hd
 
235
  )
236
 
237
  mls = torch.tanh(self.W_prior(h_dec))
238
- mu_p, ls_p = mls[:, :self.Z], mls[:, self.Z:]
239
 
240
- gx, gy, dl, sg, gm = self.writer.params(self.W_write(h_dec))
 
 
 
 
 
241
 
242
  win = self.W_c(h_dec).view(
243
  b, self.C, self.Nw, self.Nw
@@ -249,7 +322,11 @@ class AlignDRAW(nn.Module):
249
  ).reshape(b, -1)
250
 
251
  c_final = torch.sigmoid(c)
252
- bce = F.binary_cross_entropy(c_final, x, reduction="sum")
 
 
 
 
253
  kl = 0.5 * kl
254
 
255
  return {
@@ -260,13 +337,16 @@ class AlignDRAW(nn.Module):
260
 
261
  @torch.no_grad()
262
  def generate(self, y, steps=None, return_seq=False):
 
263
  steps = self.T if steps is None else steps
264
 
265
  b = y.shape[0]
266
  dev = self.h0_dec.device
267
 
268
  h_dec = self.h0_dec.expand(b, -1).contiguous()
269
- cell_dec = torch.zeros(b, self.Hd, device=dev)
 
 
270
 
271
  c = self.c0.expand(b, -1).contiguous()
272
 
@@ -274,25 +354,34 @@ class AlignDRAW(nn.Module):
274
  ls_p = torch.zeros(b, self.Z, device=dev)
275
 
276
  hlang, hid_align = self.encode_caption(y)
 
277
  seq = []
278
 
279
  for _ in range(steps):
 
280
  z = mu_p + torch.exp(ls_p) * torch.randn_like(mu_p)
281
 
282
- s, _ = self._align(hlang, hid_align, h_dec)
 
 
283
 
284
  h_dec, cell_dec = _lstm(
285
  self.Wh_dec(h_dec)
286
  + self.Wz_dec(z)
287
  + self.W_s_hdec(s)
288
  + self.b_dec,
289
- cell_dec, self.Hd
 
290
  )
291
 
292
  mls = torch.tanh(self.W_prior(h_dec))
293
- mu_p, ls_p = mls[:, :self.Z], mls[:, self.Z:]
294
 
295
- gx, gy, dl, sg, gm = self.writer.params(self.W_write(h_dec))
 
 
 
 
 
296
 
297
  win = self.W_c(h_dec).view(
298
  b, self.C, self.Nw, self.Nw
 
1
 
2
+ """AlignDRAW 512x512
3
+ Based on the supplied AlignDRAW PyTorch implementation.
4
+ Image resolution: 512x512
5
+ DRAW generation steps: 69
6
+ Requires a newly trained checkpoint.
7
  """
8
 
9
  import torch
 
12
 
13
 
14
  def _lstm(pre, cell, H):
15
+ i = torch.sigmoid(pre[:, 0:H])
16
+ f = torch.sigmoid(pre[:, H:2*H])
17
+ g = torch.tanh(pre[:, 2*H:3*H])
18
+ o = torch.sigmoid(pre[:, 3*H:4*H])
19
  cell = f * cell + i * g
20
  return o * torch.tanh(cell), cell
21
 
 
33
  return gx, gy, delta, sigma, gamma
34
 
35
  def _fb(self, g, delta, sigma, size):
36
+ grid = torch.arange(
37
+ self.N, device=g.device, dtype=g.dtype
38
+ ) - self.N // 2 - 0.5
39
+
40
  mu = g.unsqueeze(1) + delta.unsqueeze(1) * grid.unsqueeze(0)
41
+ a = torch.arange(size, device=g.device, dtype=g.dtype)
42
+
43
  fb = torch.exp(
44
  -((a.view(1, 1, -1) - mu.unsqueeze(2)) ** 2)
45
  / (2 * sigma.view(-1, 1, 1) ** 2 + 1e-8)
46
  )
47
+
48
  return fb / (fb.sum(-1, keepdim=True) + 1e-4)
49
 
50
  def read(self, img, gx, gy, delta, sigma):
51
  Fx = self._fb(gx, delta, sigma, self.W)
52
  Fy = self._fb(gy, delta, sigma, self.H)
53
+
54
  t = torch.einsum('bnh,bchw->bcnw', Fy, img)
55
  return torch.einsum('bcnw,bmw->bcnm', t, Fx)
56
 
57
  def write(self, win, gx, gy, delta, sigma):
58
  Fx = self._fb(gx, delta, sigma, self.W)
59
  Fy = self._fb(gy, delta, sigma, self.H)
60
+
61
  t = torch.einsum('bnh,bcnm->bchm', Fy, win)
62
  return torch.einsum('bchm,bmw->bchw', t, Fx)
63
 
64
 
65
  class AlignDRAW(nn.Module):
66
+
67
  def __init__(
68
  self,
69
  dimY=25323,
70
  dimLangRNN=128,
71
  dimAlign=512,
72
+ imgSize=512,
73
  dimReadAttent=9,
74
  dimWriteAttent=9,
75
  dimRNNEnc=550,
 
81
 
82
  self.C = 3
83
  self.H = self.W = imgSize
84
+ self.dimX = self.C * self.H * self.W
85
 
86
  self.Nr, self.Nw = dimReadAttent, dimWriteAttent
87
+ self.He, self.Hd = dimRNNEnc, dimRNNDec
88
+ self.Z, self.T = dimZ, runSteps
89
  self.Hl, self.Al = dimLangRNN, dimAlign
90
 
91
+ # Bidirectional language encoder
92
  self.emb_f = nn.Embedding(dimY, 4 * dimLangRNN)
93
  self.Wh_f = nn.Linear(dimLangRNN, 4 * dimLangRNN, bias=False)
94
  self.b_f = nn.Parameter(torch.zeros(4 * dimLangRNN))
 
97
  self.Wh_b = nn.Linear(dimLangRNN, 4 * dimLangRNN, bias=False)
98
  self.b_b = nn.Parameter(torch.zeros(4 * dimLangRNN))
99
 
100
+ # Caption alignment
101
+ self.W_lang_align = nn.Linear(
102
+ 2 * dimLangRNN, dimAlign, bias=False
103
+ )
104
+ self.W_hdec_align = nn.Linear(
105
+ dimRNNDec, dimAlign, bias=False
106
+ )
107
+
108
  self.b_align = nn.Parameter(torch.zeros(dimAlign))
109
  self.v_align = nn.Parameter(torch.randn(dimAlign) * 0.01)
 
110
 
111
+ self.W_s_hdec = nn.Linear(
112
+ 2 * dimLangRNN, 4 * dimRNNDec, bias=False
113
+ )
114
+
115
+ # Image reader
116
  self.W_read = nn.Linear(dimRNNDec, 5)
117
+
118
  read_dim = 2 * self.C * self.Nr * self.Nr
119
 
120
+ # Encoder LSTM
121
+ self.Wh_enc = nn.Linear(
122
+ dimRNNEnc, 4 * dimRNNEnc, bias=False
123
+ )
124
+
125
+ self.Wi_enc = nn.Linear(
126
+ read_dim + dimRNNDec,
127
+ 4 * dimRNNEnc,
128
+ bias=False
129
+ )
130
+
131
  self.b_enc = nn.Parameter(torch.zeros(4 * dimRNNEnc))
132
 
133
  self.W_mu = nn.Linear(dimRNNEnc, dimZ)
134
  self.W_logsigma = nn.Linear(dimRNNEnc, dimZ)
135
 
136
  # Decoder and learned prior
137
+ self.Wh_dec = nn.Linear(
138
+ dimRNNDec, 4 * dimRNNDec, bias=False
139
+ )
140
+
141
+ self.Wz_dec = nn.Linear(
142
+ dimZ, 4 * dimRNNDec, bias=False
143
+ )
144
+
145
  self.b_dec = nn.Parameter(torch.zeros(4 * dimRNNDec))
146
  self.W_prior = nn.Linear(dimRNNDec, 2 * dimZ)
147
 
148
+ # Image writer
149
  self.W_write = nn.Linear(dimRNNDec, 5)
 
150
 
151
+ self.W_c = nn.Linear(
152
+ dimRNNDec, self.C * self.Nw * self.Nw
153
+ )
154
+
155
+ # Full 512x512 canvas initialization
156
  self.h0_lang = nn.Parameter(torch.zeros(1, dimLangRNN))
157
  self.h0_enc = nn.Parameter(torch.zeros(1, dimRNNEnc))
158
  self.h0_dec = nn.Parameter(torch.zeros(1, dimRNNDec))
159
+
160
  self.c0 = nn.Parameter(torch.zeros(1, self.dimX))
161
 
162
+ self.reader = SelectiveAttention(
163
+ self.H, self.W, self.Nr
164
+ )
165
+
166
+ self.writer = SelectiveAttention(
167
+ self.H, self.W, self.Nw
168
+ )
169
 
170
  self._init_weights()
171
 
 
173
  for m in self.modules():
174
  if isinstance(m, (nn.Linear, nn.Embedding)):
175
  nn.init.normal_(m.weight, 0.0, 0.01)
176
+
177
  if getattr(m, "bias", None) is not None:
178
  nn.init.zeros_(m.bias)
179
 
 
194
  self.emb_f(y[:, t]) + self.Wh_f(hf) + self.b_f,
195
  cf, self.Hl
196
  )
197
+
198
  hb, cb = _lstm(
199
  self.emb_b(yr[:, t]) + self.Wh_b(hb) + self.b_b,
200
  cb, self.Hl
201
  )
202
+
203
  outs_f.append(hf)
204
  outs_b.append(hb)
205
 
206
  hlang = torch.cat(
207
+ [
208
+ torch.stack(outs_f, 1),
209
+ torch.stack(outs_b, 1)
210
+ ],
211
  dim=2
212
  )
213
 
 
215
 
216
  def _align(self, hlang, hid_align, h_dec):
217
  e = torch.tanh(
218
+ hid_align
219
+ + self.W_hdec_align(h_dec).unsqueeze(1)
220
+ + self.b_align
221
  )
222
+
223
  e = (e * self.v_align).sum(-1)
224
  alpha = F.softmax(e, dim=1)
225
+
226
  s = (alpha.unsqueeze(2) * hlang).sum(1)
227
+
228
  return s, alpha
229
 
230
  def forward(self, x, y):
231
  b = x.shape[0]
232
 
233
+ assert x.shape[1] == self.dimX, (
234
+ f"Expected {self.dimX} image values, got {x.shape[1]}"
235
+ )
236
+
237
  h_dec = self.h0_dec.expand(b, -1).contiguous()
238
  cell_dec = x.new_zeros(b, self.Hd)
239
 
 
246
  ls_p = x.new_zeros(b, self.Z)
247
 
248
  hlang, hid_align = self.encode_caption(y)
249
+
250
  ximg = x.view(b, self.C, self.H, self.W)
251
 
252
  kl = x.new_zeros(())
253
 
254
  for _ in range(self.T):
255
+
256
  x_hat = ximg - torch.sigmoid(c).view(
257
  b, self.C, self.H, self.W
258
  )
259
 
260
+ gx, gy, dl, sg, gm = self.reader.params(
261
+ self.W_read(h_dec)
262
+ )
263
 
264
+ r = gm[:, :, None, None] * torch.cat(
265
+ [
266
+ self.reader.read(ximg, gx, gy, dl, sg),
267
+ self.reader.read(x_hat, gx, gy, dl, sg)
268
+ ],
269
+ dim=1
270
+ )
271
 
272
  r = r.reshape(b, -1)
273
 
 
277
  self.Wh_enc(h_enc)
278
  + self.Wi_enc(torch.cat([r, h_dec], 1))
279
  + self.b_enc,
280
+ cell_enc,
281
+ self.He
282
  )
283
 
284
  mu = self.W_mu(h_enc)
 
288
 
289
  kl = kl + torch.sum(
290
  -1
291
+ + (
292
+ (mu - mu_p) ** 2 + torch.exp(2 * ls)
293
+ ) / torch.exp(2 * ls_p)
294
  - 2 * ls + 2 * ls_p
295
  )
296
 
 
299
  + self.Wz_dec(z)
300
  + self.W_s_hdec(s)
301
  + self.b_dec,
302
+ cell_dec,
303
+ self.Hd
304
  )
305
 
306
  mls = torch.tanh(self.W_prior(h_dec))
 
307
 
308
+ mu_p = mls[:, :self.Z]
309
+ ls_p = mls[:, self.Z:]
310
+
311
+ gx, gy, dl, sg, gm = self.writer.params(
312
+ self.W_write(h_dec)
313
+ )
314
 
315
  win = self.W_c(h_dec).view(
316
  b, self.C, self.Nw, self.Nw
 
322
  ).reshape(b, -1)
323
 
324
  c_final = torch.sigmoid(c)
325
+
326
+ bce = F.binary_cross_entropy(
327
+ c_final, x, reduction="sum"
328
+ )
329
+
330
  kl = 0.5 * kl
331
 
332
  return {
 
337
 
338
  @torch.no_grad()
339
  def generate(self, y, steps=None, return_seq=False):
340
+
341
  steps = self.T if steps is None else steps
342
 
343
  b = y.shape[0]
344
  dev = self.h0_dec.device
345
 
346
  h_dec = self.h0_dec.expand(b, -1).contiguous()
347
+ cell_dec = torch.zeros(
348
+ b, self.Hd, device=dev
349
+ )
350
 
351
  c = self.c0.expand(b, -1).contiguous()
352
 
 
354
  ls_p = torch.zeros(b, self.Z, device=dev)
355
 
356
  hlang, hid_align = self.encode_caption(y)
357
+
358
  seq = []
359
 
360
  for _ in range(steps):
361
+
362
  z = mu_p + torch.exp(ls_p) * torch.randn_like(mu_p)
363
 
364
+ s, _ = self._align(
365
+ hlang, hid_align, h_dec
366
+ )
367
 
368
  h_dec, cell_dec = _lstm(
369
  self.Wh_dec(h_dec)
370
  + self.Wz_dec(z)
371
  + self.W_s_hdec(s)
372
  + self.b_dec,
373
+ cell_dec,
374
+ self.Hd
375
  )
376
 
377
  mls = torch.tanh(self.W_prior(h_dec))
 
378
 
379
+ mu_p = mls[:, :self.Z]
380
+ ls_p = mls[:, self.Z:]
381
+
382
+ gx, gy, dl, sg, gm = self.writer.params(
383
+ self.W_write(h_dec)
384
+ )
385
 
386
  win = self.W_c(h_dec).view(
387
  b, self.C, self.Nw, self.Nw