{"version":2,"relationshipURLBase":"https://codingai-lec03.pages.dev/course/notebook-blocks/57c45842cea34b3f94d8cebb61d29d93.html","relationshipResolution":"Resolve relative relationship URLs against relationshipURLBase; complete records and absolute URLs are in blocks.","title":"3. 运行比较：用验证集选每组的停点 · 实现代码","url":"https://codingai-lec03.pages.dev/course/notebook-blocks/57c45842cea34b3f94d8cebb61d29d93.html","markdown":"https://codingai-lec03.pages.dev/course/notebook-blocks/57c45842cea34b3f94d8cebb61d29d93.md","pages":[{"id":"reading-opening","title":"3. 运行比较：用验证集选每组的停点 · 实现代码","unit":"3. 运行比较：用验证集选每组的停点 · 实现代码","unitId":"notebook-blocks/57c45842cea34b3f94d8cebb61d29d93","chapter":"course","number":1}],"aliases":[{"oldId":"b-b54732d726e66abb4d4960eb","targetId":"b-b54732d726e66abb4d4960eb","page":"reading-opening","operation":"move","beforeSHA256":"f107bd31e942a5cf605f3183c89731efbb5349a4bf8c063087e5d29bebde50b5","afterSHA256":"f107bd31e942a5cf605f3183c89731efbb5349a4bf8c063087e5d29bebde50b5","reason":"Same source body in authored semantic page"},{"oldId":"b-29b19a74a799e06bb8204fcb","targetId":"b-29b19a74a799e06bb8204fcb","page":"reading-opening","operation":"move","beforeSHA256":"82dfb7a86aab43f2aa8de278fcb71d679c50aa26d9842c57abb2b1bff98d2d44","afterSHA256":"82dfb7a86aab43f2aa8de278fcb71d679c50aa26d9842c57abb2b1bff98d2d44","reason":"Same source body in authored semantic page"},{"oldId":"b-b4177aaf5eda13ba6ad8f379","targetId":"b-b4177aaf5eda13ba6ad8f379","page":"reading-opening","operation":"move","beforeSHA256":"e91f24e4e4ca40e2099a0d81d30db6568f4bf2074b499eeee6e3959617bd97ac","afterSHA256":"e91f24e4e4ca40e2099a0d81d30db6568f4bf2074b499eeee6e3959617bd97ac","reason":"Same source body in authored semantic page"},{"oldId":"b-821dce9714fa5aa97a275757","targetId":"b-821dce9714fa5aa97a275757","page":"reading-opening","operation":"move","beforeSHA256":"5f1e2e7a35a6afaca427b0b03cfec448b4aac4324b16108f14671986a2d98b38","afterSHA256":"5f1e2e7a35a6afaca427b0b03cfec448b4aac4324b16108f14671986a2d98b38","reason":"Same source body in authored semantic page"},{"oldId":"b-432a1cf4986be970baa9102f","targetId":"b-432a1cf4986be970baa9102f","page":"reading-opening","operation":"move","beforeSHA256":"0d895fee1d544d1219f5704ce4ce47b623f9d946f397f4864637896fee477584","afterSHA256":"0d895fee1d544d1219f5704ce4ce47b623f9d946f397f4864637896fee477584","reason":"Same source body in authored semantic page"}],"blocks":[{"id":"b-b54732d726e66abb4d4960eb","type":"p","scope":"document","url":"https://codingai-lec03.pages.dev/course/notebook-blocks/57c45842cea34b3f94d8cebb61d29d93.html#b-b54732d726e66abb4d4960eb","content":"[LAB 02 · 参数迁移：冻结、局部与全量微调](/course/notebooks/4bd450d54870432db91c80a4df563b8e.html)","sha256":"f107bd31e942a5cf605f3183c89731efbb5349a4bf8c063087e5d29bebde50b5","chapter":{"id":"course","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"unit":{"id":"notebook-blocks/57c45842cea34b3f94d8cebb61d29d93","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"page":{"id":"reading-opening","title":"3. 运行比较：用验证集选每组的停点 · 实现代码","number":1},"sectionTitle":"3. 运行比较：用验证集选每组的停点 · 实现代码","currentQuestion":"3. 运行比较：用验证集选每组的停点 · 实现代码","sourceSlides":[],"knowledgeBlock":null,"formulas":[],"previousBlock":null,"nextBlock":"b-29b19a74a799e06bb8204fcb","prerequisites":[],"relatedBlocks":[]},{"id":"b-29b19a74a799e06bb8204fcb","type":"h1","scope":"document","url":"https://codingai-lec03.pages.dev/course/notebook-blocks/57c45842cea34b3f94d8cebb61d29d93.html#b-29b19a74a799e06bb8204fcb","content":"# 3. 运行比较：用验证集选每组的停点 · 实现代码","sha256":"82dfb7a86aab43f2aa8de278fcb71d679c50aa26d9842c57abb2b1bff98d2d44","chapter":{"id":"course","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"unit":{"id":"notebook-blocks/57c45842cea34b3f94d8cebb61d29d93","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"page":{"id":"reading-opening","title":"3. 运行比较：用验证集选每组的停点 · 实现代码","number":1},"sectionTitle":"3. 运行比较：用验证集选每组的停点 · 实现代码","currentQuestion":"3. 运行比较：用验证集选每组的停点 · 实现代码","sourceSlides":[],"knowledgeBlock":null,"formulas":[],"previousBlock":"b-b54732d726e66abb4d4960eb","nextBlock":"b-b4177aaf5eda13ba6ad8f379","prerequisites":[{"id":"b-b54732d726e66abb4d4960eb","url":"#b-b54732d726e66abb4d4960eb","role":"problem-context"}],"relatedBlocks":[]},{"id":"b-b4177aaf5eda13ba6ad8f379","type":"p","scope":"document","url":"https://codingai-lec03.pages.dev/course/notebook-blocks/57c45842cea34b3f94d8cebb61d29d93.html#b-b4177aaf5eda13ba6ad8f379","content":"按问题继续","sha256":"e91f24e4e4ca40e2099a0d81d30db6568f4bf2074b499eeee6e3959617bd97ac","chapter":{"id":"course","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"unit":{"id":"notebook-blocks/57c45842cea34b3f94d8cebb61d29d93","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"page":{"id":"reading-opening","title":"3. 运行比较：用验证集选每组的停点 · 实现代码","number":1},"sectionTitle":"3. 运行比较：用验证集选每组的停点 · 实现代码","currentQuestion":"3. 运行比较：用验证集选每组的停点 · 实现代码","sourceSlides":[],"knowledgeBlock":null,"formulas":[],"previousBlock":"b-29b19a74a799e06bb8204fcb","nextBlock":"b-821dce9714fa5aa97a275757","prerequisites":[{"id":"b-29b19a74a799e06bb8204fcb","url":"#b-29b19a74a799e06bb8204fcb","role":"section-title"},{"id":"b-b54732d726e66abb4d4960eb","url":"#b-b54732d726e66abb4d4960eb","role":"problem-context"}],"relatedBlocks":[]},{"id":"b-821dce9714fa5aa97a275757","type":"p","scope":"document","url":"https://codingai-lec03.pages.dev/course/notebook-blocks/57c45842cea34b3f94d8cebb61d29d93.html#b-821dce9714fa5aa97a275757","content":"同源参数的冻结/局部/全量/scratch与BN模式辨析","sha256":"5f1e2e7a35a6afaca427b0b03cfec448b4aac4324b16108f14671986a2d98b38","chapter":{"id":"course","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"unit":{"id":"notebook-blocks/57c45842cea34b3f94d8cebb61d29d93","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"page":{"id":"reading-opening","title":"3. 运行比较：用验证集选每组的停点 · 实现代码","number":1},"sectionTitle":"3. 运行比较：用验证集选每组的停点 · 实现代码","currentQuestion":"3. 运行比较：用验证集选每组的停点 · 实现代码","sourceSlides":[],"knowledgeBlock":null,"formulas":[],"previousBlock":"b-b4177aaf5eda13ba6ad8f379","nextBlock":"b-432a1cf4986be970baa9102f","prerequisites":[{"id":"b-29b19a74a799e06bb8204fcb","url":"#b-29b19a74a799e06bb8204fcb","role":"section-title"},{"id":"b-b54732d726e66abb4d4960eb","url":"#b-b54732d726e66abb4d4960eb","role":"problem-context"}],"relatedBlocks":[]},{"id":"b-432a1cf4986be970baa9102f","type":"pre","scope":"document","url":"https://codingai-lec03.pages.dev/course/notebook-blocks/57c45842cea34b3f94d8cebb61d29d93.html#b-432a1cf4986be970baa9102f","content":"```\n@torch.no_grad()\ndef evaluate_binary(model,xx,yy):\n    model.eval();scores=model(xx)\n    return {'ce':float(F.cross_entropy(scores,yy)), 'accuracy':float((scores.argmax(1)==yy).float().mean())}\ntorch.use_deterministic_algorithms(True)\ngenerator=torch.Generator().manual_seed(SEED+2)\norders=[torch.randperm(len(train_y),generator=generator) for _ in range(EPOCHS)]\nmodels={};records={}\nfor mode in MODES:\n    model=make_target_model(mode)\n    frozen_before={n:p.detach().clone() for n,p in model.named_parameters() if not p.requires_grad}\n    optimizer=torch.optim.Adam([p for p in model.parameters() if p.requires_grad],lr=LEARNING_RATE)\n    best_ce=float('inf');history=[];start=time.perf_counter()\n    for epoch,order in enumerate(orders,1):\n        model.train()\n        for ids in order.split(BATCH_SIZE):\n            optimizer.zero_grad();loss=F.cross_entropy(model(train_x[ids]),train_y[ids]);loss.backward();optimizer.step()\n        tr=evaluate_binary(model,train_x,train_y);va=evaluate_binary(model,val_x,val_y)\n        history.append({'epoch':epoch,'train_ce':tr['ce'],'val_ce':va['ce'],'val_accuracy':va['accuracy']})\n        if va['ce']<best_ce:\n            best_ce=va['ce'];best_state=copy.deepcopy(model.state_dict());selected=epoch\n    elapsed=time.perf_counter()-start\n    model.load_state_dict(best_state)\n    for name,param in model.named_parameters():\n        if name in frozen_before: assert torch.equal(param.detach(),frozen_before[name]),name\n    models[mode]=model\n    records[mode]={'selected_epoch':selected,'train':evaluate_binary(model,train_x,train_y),\n                   'validation':evaluate_binary(model,val_x,val_y),'seconds':elapsed,'history':history}\nfig,axes=plt.subplots(1,2,figsize=(10,3.5),sharey=True)\nfor mode,r in records.items():\n    axes[0].plot([v['epoch'] for v in r['history']],[v['train_ce'] for v in r['history']],label=mode)\n    axes[1].plot([v['epoch'] for v in r['history']],[v['val_ce'] for v in r['history']],label=mode)\n    chosen=next(v for v in r['history'] if v['epoch']==r['selected_epoch'])\n    axes[1].scatter([chosen['epoch']],[chosen['val_ce']],facecolors='none',edgecolors=axes[1].lines[-1].get_color(),s=75,zorder=3)\nymax=max(v[key] for r in records.values() for v in r['history'] for key in ('train_ce','val_ce'))\naxes[0].set_ylim(0,max(ymax*1.05,1e-8))\naxes[0].set_ylabel('Cross-entropy (same scale)')\naxes[0].set_title('training CE');axes[1].set_title('validation CE')\nfor ax in axes:ax.set_xlabel('epoch');ax.legend()\nplt.tight_layout();plt.show()\nprint(json.dumps({m:{k:v for k,v in r.items() if k!='history'} for m,r in records.items()},indent=2))\n\n```","sha256":"0d895fee1d544d1219f5704ce4ce47b623f9d946f397f4864637896fee477584","chapter":{"id":"course","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"unit":{"id":"notebook-blocks/57c45842cea34b3f94d8cebb61d29d93","title":"3. 运行比较：用验证集选每组的停点 · 实现代码"},"page":{"id":"reading-opening","title":"3. 运行比较：用验证集选每组的停点 · 实现代码","number":1},"sectionTitle":"3. 运行比较：用验证集选每组的停点 · 实现代码","currentQuestion":"3. 运行比较：用验证集选每组的停点 · 实现代码","sourceSlides":[],"knowledgeBlock":null,"formulas":[],"previousBlock":"b-821dce9714fa5aa97a275757","nextBlock":null,"prerequisites":[{"id":"b-29b19a74a799e06bb8204fcb","url":"#b-29b19a74a799e06bb8204fcb","role":"section-title"},{"id":"b-b54732d726e66abb4d4960eb","url":"#b-b54732d726e66abb4d4960eb","role":"problem-context"}],"relatedBlocks":[]}]}
