[LAB 05 · 像素 patch 词典:拟合与重建](/course/notebooks/de39b998077f44cca4b8407085547766.html) # 1 · 没有类别标签,词典到底学了什么? · 实现代码 [独立阅读](/course/notebook-blocks/e56644fbd8a5464084c3e83da669726c.html) 按问题继续 真实MNIST patch的Lloyd拟合、词典中心、保留误差与历史输出 展开完整实现代码 ``` # Actual Lloyd updates on image patches. Labels are deliberately absent from fit(). N_WORDS=16 PATCH=7 patches=x.reshape(640,1,4,PATCH,4,PATCH).transpose(0,2,4,1,3,5).reshape(640,16,PATCH*PATCH) fit_patches=patches[train].reshape(-1,PATCH*PATCH) fit_patches=fit_patches[fit_patches.mean(1)>.01].astype(np.float64) def fit_lloyd_unlabeled(a,k,seed=20260918,max_iter=80): rng=np.random.default_rng(seed) centers=a[rng.choice(len(a),k,replace=False)].copy() trace=[] for iteration in range(max_iter): distances=((a[:,None,:]-centers[None,:,:])**2).sum(2) assignments=distances.argmin(1) new=np.stack([a[assignments==j].mean(0) if np.any(assignments==j) else centers[j] for j in range(k)]) new_distances=((a[:,None,:]-new[None,:,:])**2).sum(2) sse=float(new_distances.min(1).sum()) trace.append(sse) if np.allclose(new,centers,rtol=0,atol=1e-10): centers=new; break centers=new assert np.all(np.diff(trace)<=1e-7) return centers,trace centers,trace=fit_lloyd_unlabeled(fit_patches,N_WORDS) frozen_centers=centers.copy() test_patches=patches[heldout].reshape(-1,49) test_dist=((test_patches[:,None,:]-frozen_centers[None,:,:])**2).sum(2) test_assignment=test_dist.argmin(1) assert np.array_equal(centers,frozen_centers) kmeans_result={'identity':'L-A true MNIST pixel-patch Lloyd fit','labels_used_in_fit':False, 'patch_shape':[7,7],'n_words':N_WORDS,'train_images':len(train),'train_nonblank_patches':len(fit_patches), 'fit_sample_ids':sample_ids[train].tolist(),'evaluation_sample_ids':sample_ids[heldout].tolist(), 'train_sse_trace':trace,'heldout_mean_squared_pixel_error':float(test_dist.min(1).mean()/49), 'warning':'train excludes nearblank patches; heldout covers all patches, so these objectives are not identically weighted'} np.savez_compressed(OUT/'kmeans-centers.npz',centers=centers) (OUT/'kmeans-results.json').write_text(json.dumps(kmeans_result,indent=2)) fig=plt.figure(figsize=(12,4.4),layout='constrained') outer=fig.add_gridspec(1,2,width_ratios=[1,1.3],wspace=.12) grid=outer[0].subgridspec(int(np.ceil(N_WORDS/4)),4,wspace=.06,hspace=.12) for j,c in enumerate(centers): ax=fig.add_subplot(grid[j//4,j%4]);ax.imshow(c.reshape(7,7),cmap='gray',vmin=0,vmax=1);ax.set_title(f'word {j}',fontsize=8);ax.axis('off') ax=fig.add_subplot(outer[1]);ax.plot(np.arange(1,len(trace)+1),trace,color=BLUE,marker='.',ms=4) ax.set(xlabel='Lloyd iteration',ylabel='Training sum of squared distances',title='Real image patches; no digit labels') savefig('02-unlabeled-fit.png') print('Fitted nonblank patches:',len(fit_patches),'iterations:',len(trace)) print('Held-out pixel reconstruction MSE:',kmeans_result['heldout_mean_squared_pixel_error']) ```