{"id":"5exuaaxywU","url":"https://pastebin.ca/5exuaaxywU","raw_url":"https://raw.anybin.ca/5exuaaxywU","visibility":"public","access":"public","created_at":1793950234448,"expires_at":1794555034448,"fetch_limit":null,"fetches_used":0,"reads_remaining":null,"size_bytes":4585,"syntax_hint":null,"title":null,"filename":null,"change_note":null,"cipher":null,"cipher_meta":null,"parent_id":null,"root_id":"5exuaaxywU","version":1,"owner_id":null,"recipient_id":null,"body":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import StandardScaler\n\n# ========== 全局配置 中文+随机种子 ==========\nplt.rcParams['font.sans-serif'] = ['SimHei']\nplt.rcParams['axes.unicode_minus'] = False\ntorch.manual_seed(42)\nnp.random.seed(42)\n\n# ========== 1.读取并预处理数据 ==========\ndf = pd.read_csv(\"pima-diabetes.csv\")\nX = df.drop(\"Outcome\", axis=1).values\ny = df[\"Outcome\"].values.reshape(-1, 1)\n\n# 划分训练集、测试集，分层抽样保证正负样本比例\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.2, random_state=42, stratify=y\n)\nscaler = StandardScaler()\nX_train = scaler.fit_transform(X_train)\nX_test = scaler.transform(X_test)\n\n# 转为torch张量\nX_train = torch.tensor(X_train, dtype=torch.float32)\ny_train = torch.tensor(y_train, dtype=torch.float32)\nX_test = torch.tensor(X_test, dtype=torch.float32)\ny_test = torch.tensor(y_test, dtype=torch.float32)\n\n# ========== 2.定义网络 ==========\nclass DiabetesNet(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.net = nn.Sequential(\n            nn.Linear(8, 64),\n            nn.ReLU(),\n            nn.Linear(64, 32),\n            nn.ReLU(),\n            nn.Linear(32, 1),\n            nn.Sigmoid()\n        )\n    def forward(self, x):\n        return self.net(x)\n\nloss_fn = nn.BCELoss()\nlr = 0.001\nmax_epoch = 150\n\n# ===================== 第一部分：无早停，完整训练（观察过拟合） =====================\nprint(\"===== 开始无早停训练 =====\")\nmodel1 = DiabetesNet()\nopt1 = optim.Adam(model1.parameters(), lr=lr)\ntrain_loss_no_early = []\ntest_loss_no_early = []\n\nfor epoch in range(max_epoch):\n    model1.train()\n    opt1.zero_grad()\n    pred_train = model1(X_train)\n    tr_loss = loss_fn(pred_train, y_train)\n    tr_loss.backward()\n    opt1.step()\n\n    model1.eval()\n    with torch.no_grad():\n        pred_test = model1(X_test)\n        te_loss = loss_fn(pred_test, y_test)\n\n    train_loss_no_early.append(tr_loss.item())\n    test_loss_no_early.append(te_loss.item())\n    if (epoch+1) % 20 == 0:\n        print(f\"Epoch {epoch+1:3d} | Train:{tr_loss:.4f} | Test:{te_loss:.4f}\")\n\n# 绘图：无早停loss曲线\nplt.figure(figsize=(8, 5))\nplt.plot(train_loss_no_early, label=\"Train Loss\")\nplt.plot(test_loss_no_early, label=\"Test Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.title(\"Training and Testing Loss Curves（无早停，出现过拟合）\")\nplt.legend()\nplt.grid(alpha=0.3)\nplt.tight_layout()\nplt.savefig(\"loss_no_earlystop.jpg\", dpi=300)\nplt.show()\n\n# ===================== 第二部分：带早停法训练 =====================\nprint(\"\\n===== 开始带早停训练 =====\")\nmodel2 = DiabetesNet()\nopt2 = optim.Adam(model2.parameters(), lr=lr)\ntrain_loss_early = []\ntest_loss_early = []\npatience = 15          # 连续15轮测试loss不下降就停止\nbest_test_loss = float(\"inf\")\nwait = 0\nstop_epoch = max_epoch # 记录停止轮次\n\nfor epoch in range(max_epoch):\n    model2.train()\n    opt2.zero_grad()\n    pred_train = model2(X_train)\n    tr_loss = loss_fn(pred_train, y_train)\n    tr_loss.backward()\n    opt2.step()\n\n    model2.eval()\n    with torch.no_grad():\n        pred_test = model2(X_test)\n        te_loss = loss_fn(pred_test, y_test)\n\n    train_loss_early.append(tr_loss.item())\n    test_loss_early.append(te_loss.item())\n\n    # 早停判断逻辑\n    if te_loss < best_test_loss:\n        best_test_loss = te_loss\n        wait = 0\n    else:\n        wait += 1\n        if wait >= patience:\n            stop_epoch = epoch + 1\n            print(f\"✅ 触发早停，Epoch={stop_epoch}，最佳测试损失：{best_test_loss:.4f}\")\n            break\n\n    if (epoch+1) % 20 == 0:\n        print(f\"Epoch {epoch+1:3d} | Train:{tr_loss:.4f} | Test:{te_loss:.4f}\")\n\n# 绘图：带早停loss曲线，标记停止点\nplt.figure(figsize=(8, 5))\nplt.plot(train_loss_early, label=\"Train Loss\")\nplt.plot(test_loss_early, label=\"Test Loss\")\nplt.axvline(x=stop_epoch-1, color=\"red\", linestyle=\"--\", label=f\"早停点 Epoch={stop_epoch}\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.title(\"Training and Testing Loss Curves（加入早停法 Early Stopping）\")\nplt.legend()\nplt.grid(alpha=0.3)\nplt.tight_layout()\nplt.savefig(\"loss_with_earlystop.jpg\", dpi=300)\nplt.show()\n\nprint(\"\\n✅ 全部训练完成，两张图片已保存：\")\nprint(\"loss_no_earlystop.jpg    无早停（过拟合对照）\")\nprint(\"loss_with_earlystop.jpg  带早停法\")\n"}