text paste
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.metrics import r2_score

# ---------------------- 全局设置 中文+随机种子 ----------------------
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
torch.manual_seed(42)
np.random.seed(42)

# 读取数据
df = pd.read_csv("data.csv")
x_raw = df[['x']].values.astype(np.float32)
y_raw = df[['y']].values.astype(np.float32)
x_tensor = torch.from_numpy(x_raw)
y_tensor = torch.from_numpy(y_raw)

# 神经网络定义:单层隐藏层,GELU激活
class MLP(nn.Module):
    def __init__(self, hidden_n):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(1, hidden_n),
            nn.GELU(),
            nn.Linear(hidden_n, 1)
        )
    def forward(self, x):
        return self.net(x)

# ---------------------- 任务2:不同隐藏节点n,cosine decay,lr=0.01,epoch=10000 ----------------------
n_list = [2,4,6,8,16,32]  # 6个n,正好6张子图
epoch_total = 10000
lr0 = 0.01
criterion = nn.MSELoss()

res_fit = []   # 保存预测结果
res_loss = []  # 保存loss曲线
res_r2 = []    # 保存R2
lr_record = [] # 保存学习率变化(取n=8为例)

for n in n_list:
    model = MLP(n)
    opt = optim.Adam(model.parameters(), lr=lr0)
    scheduler = optim.lr_scheduler.CosineAnnealingLR(opt, T_max=epoch_total, eta_min=0)
    loss_hist = []
    for ep in range(epoch_total):
        opt.zero_grad()
        pred = model(x_tensor)
        loss = criterion(pred, y_tensor)
        loss.backward()
        opt.step()
        scheduler.step()
        loss_hist.append(loss.item())
        if n == 8:
            lr_record.append(opt.param_groups[0]['lr'])
    # 预测 & R2
    with torch.no_grad():
        y_pred = model(x_tensor).numpy()
    r2 = r2_score(y_raw, y_pred)
    res_fit.append(y_pred)
    res_loss.append(loss_hist)
    res_r2.append(r2)

# 图1:6个子图,不同n拟合效果
fig1, axes = plt.subplots(2,3,figsize=(14,9))
axes = axes.flatten()
for i, ax in enumerate(axes):
    ax.scatter(x_raw, y_raw, s=10, label="真实数据")
    ax.plot(x_raw, res_fit[i], c='red', lw=2, label=f"n={n_list[i]}, R2={res_r2[i]:.4f}")
    ax.set_title(f"隐藏层节点数 n={n_list[i]}")
    ax.legend()
    ax.grid(alpha=0.3)
fig1.suptitle("不同隐藏层节点数的拟合效果", fontsize=15)
plt.tight_layout()
plt.savefig("fit_compare.jpg", dpi=300)

# 图2:不同n训练损失曲线
plt.figure(figsize=(10,6))
colors = ["#e74c3c","#3498db","#2ecc71","#9b59b6","#f39c12","#1abc9c"]
for i, n in enumerate(n_list):
    plt.plot(res_loss[i], label=f"n={n}", color=colors[i])
plt.xlabel("Epoch")
plt.ylabel("MSE损失")
plt.yscale("log")
plt.title("不同隐藏层节点数的训练损失曲线")
plt.legend()
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig("loss_n_curve.jpg", dpi=300)

# 图3:cosine decay学习率变化曲线(n=8)
plt.figure(figsize=(8,5))
plt.plot(lr_record)
plt.xlabel("Epoch")
plt.ylabel("学习率")
plt.title("Cosine Decay学习率变化曲线")
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig("lr_cosine_curve.jpg", dpi=300)

# 图4:柱状图 R2对比
plt.figure(figsize=(8,5))
plt.bar([str(i) for i in n_list], res_r2, color=colors)
plt.xlabel("隐藏层节点数 n")
plt.ylabel("决定系数 R²")
plt.title("不同隐藏层节点数的决定系数对比")
plt.ylim(0, 1.05)
for idx,val in enumerate(res_r2):
    plt.text(idx, val+0.01, f"{val:.4f}", ha="center")
plt.tight_layout()
plt.savefig("r2_bar.jpg", dpi=300)

# ---------------------- 任务3:固定n=8,关闭cosine decay,lr=[0.001,0.01,0.1,1] ----------------------
lr_test_list = [0.001, 0.01, 0.1, 1.0]
loss_lr_all = []
for lr in lr_test_list:
    model = MLP(hidden_n=8)
    opt = optim.Adam(model.parameters(), lr=lr)
    # 不设置scheduler,lr固定不变
    loss_hist = []
    for ep in range(epoch_total):
        opt.zero_grad()
        pred = model(x_tensor)
        loss = criterion(pred, y_tensor)
        loss.backward()
        opt.step()
        loss_hist.append(loss.item())
    loss_lr_all.append(loss_hist)

# 图5:不同学习率损失曲线
fig2, axes = plt.subplots(2,2,figsize=(12,9))
axes = axes.flatten()
for i, ax in enumerate(axes):
    ax.plot(loss_lr_all[i])
    ax.set_title(f"学习率 lr={lr_test_list[i]}")
    ax.set_xlabel("Epoch")
    ax.set_ylabel("MSE Loss")
    ax.grid(alpha=0.3)
fig2.suptitle("不同学习率下的训练损失曲线(关闭cosine decay)", fontsize=15)
plt.tight_layout()
plt.savefig("lr_loss_compare.jpg", dpi=300)

plt.show()
print("===== 任务2结果R2 =====")
for n,r2 in zip(n_list, res_r2):
    print(f"n={n}, R2={r2:.4f}")
print("===== 全部绘图完成 =====")