[LAB 13 · 看图生成一句话:训练、解码与消融](/course/notebooks/3da47f3ee3554ee0a36e0bb6a2fdc61f.html) # 2. 图像先生成,目标句子只进入损失 · 实现代码 [独立阅读](/course/notebook-blocks/61b73cd52382467c8d10d1143808ad17.html) 按问题继续 真实CNN–GRU条件训练与greedy/beam生成、遮图/错图消融 展开完整实现代码 ``` def render_object(color, shape, position, rng): canvas = Image.new('RGB', (32,32), (244,242,236)) painter = ImageDraw.Draw(canvas) cx = {'left':8, 'center':16, 'right':24}[position] + int(rng.integers(-1,2)) cy = 16 + int(rng.integers(-4,5)); radius = int(rng.integers(4,7)) box = (cx-radius, cy-radius, cx+radius, cy+radius) if shape == 'square': painter.rectangle(box, fill=COLORS[color]) else: painter.ellipse(box, fill=COLORS[color]) arr = np.array(canvas).astype(np.float32) / 255 arr = np.clip(arr + rng.normal(0,.018,arr.shape),0,1).astype(np.float32) return arr def make_caption_data(n, seed): rng = np.random.default_rng(seed); images=[]; sequences=[]; descriptions=[] conditions = [(c,s,p) for c in COLORS for s in ['square','circle'] for p in ['left','center','right']] for i in range(n): color, shape, pos = conditions[i % len(conditions)] words = ['a',color,shape] + ([] if pos=='center' else ['on',pos]) sequence = [BOS] + [W[w] for w in words] + [EOS] sequences.append(sequence+[PAD]*(7-len(sequence))) images.append(render_object(color,shape,pos,rng)); descriptions.append(' '.join(words)) return torch.tensor(np.stack(images)).permute(0,3,1,2), torch.tensor(sequences), descriptions Xtrain, Ytrain, train_text = make_caption_data(720,13031) Xtest, Ytest, test_text = make_caption_data(180,13033) # Independent random pixels/geometry; no duplicate image crosses the split. train_hashes = {hashlib.sha256(x.numpy().tobytes()).hexdigest() for x in Xtrain} assert not train_hashes.intersection(hashlib.sha256(x.numpy().tobytes()).hexdigest() for x in Xtest) np.savez_compressed(OUT/'lab13-data.npz', train_images=Xtrain.numpy(), train_tokens=Ytrain.numpy(), test_images=Xtest.numpy(), test_tokens=Ytest.numpy()) print('images:', tuple(Xtrain.shape), tuple(Xtest.shape), 'tokens:', tuple(Ytrain.shape)) print('teacher input:', Ytrain[:3,:-1].tolist()) print('shifted target:',Ytrain[:3,1:].tolist()) print('loss mask:',Ytrain[:3,1:].ne(PAD).int().tolist()) ```