当前位置: 首页 > article >正文

【机器学习】自定义数据集 使用paddlepaddle框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测

一、使用paddlepaddle框架实现逻辑回归

1. 数据部分

  • 首先自定义了一个简单的数据集,特征 X 是 100 个随机样本,每个样本一个特征,目标值 y 基于线性关系并添加了噪声。
  • 将 numpy 数转换为Paddlepaddle张量,方便后续在模型中使用。

2. 模型定义部分

方案 1:使用 nn.Sequential 组网

代码解释

① 数据生成与转换

  • 生成自定义的特征矩阵 X 和目标值向量 y,并添加高斯噪声模拟真实数据。
  • 使用 paddle.to_tensor 将 numpy 数组转换为 PaddlePaddle 张量。

② 模型组网

  • 使用 nn.Sequential 快速构建线性回归模型,只包含一个 nn.Linear 层。

③ 损失函数和优化器

  • 选择均方误差损失函数 nn.MSELoss 和随机梯度下降优化器 paddle.optimizer.SGD

④ 模型训练

  • 进行多个轮次的训练,在每个轮次中进行前向传播、损失计算、反向传播和参数更新。
  • 记录每一轮的损失值,用于后续绘制损失曲线。

⑤ 损失曲线绘制

  • 使用 matplotlib 绘制训练损失随轮次的变化曲线,直观展示模型的训练过程。

⑥ 模型评估

  • 在无梯度计算的模式下进行预测,计算预测结果的均方误差和决定系数。

⑦ 输出模型参数

  • 获取模型的系数和截距并输出。
import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt

# 自定义数据集
# 生成 100 个样本,每个样本有 1 个特征
X = np.random.rand(100, 1).astype(np.float32)
# 根据特征生成目标值,添加一些噪声
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)

# 将 numpy 数组转换为 PaddlePaddle 张量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)

# 使用 nn.Sequential 组网
model = nn.Sequential(
    nn.Linear(1, 1)
)

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())

# 训练模型
num_epochs = 1000
losses = []
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(X)
    loss = criterion(outputs, y)
    losses.append(loss.numpy()[0])

    # 反向传播和优化
    optimizer.clear_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')

# 绘制训练损失曲线
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()

# 模型评估
with paddle.no_grad():
    y_pred = model(X).numpy()

mse = mean_squared_error(y.numpy(), y_pred)
r2 = r2_score(y.numpy(), y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")

# 输出模型的系数和截距
weights = model[0].weight.numpy()[0][0]
bias = model[0].bias.numpy()[0]
print(f"模型系数: {weights}")
print(f"模型截距: {bias}")

方案 2:单独定义,使用类的方式 class nn.Layer 组网

代码解释

此方案与方案 1 的主要区别在于模型的组网方式,具体如下:

模型组网

① 定义一个继承自 nn.Layer 的自定义模型类 LinearRegression

② 在 __init__ 方法中初始化 nn.Linear 层。

③ 在 forward 方法中定义前向传播逻辑。

后续步骤

损失函数、优化器的选择,模型训练、评估以及参数输出等步骤与方案 1 基本相同。

import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import mean_squared_error, r2_score
import matplotlib.pyplot as plt

# 自定义数据集
# 生成 100 个样本,每个样本有 1 个特征
X = np.random.rand(100, 1).astype(np.float32)
# 根据特征生成目标值,添加一些噪声
y = 2 * X + 1 + 0.3 * np.random.randn(100, 1).astype(np.float32)

# 将 numpy 数组转换为 PaddlePaddle 张量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)

# 自定义模型类,继承自 nn.Layer
class LinearRegression(nn.Layer):
    def __init__(self):
        super(LinearRegression, self).__init__()
        self.linear = nn.Linear(1, 1)

    def forward(self, x):
        return self.linear(x)

# 创建模型实例
model = LinearRegression()

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters())

# 训练模型
num_epochs = 1000
losses = []
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(X)
    loss = criterion(outputs, y)
    losses.append(loss.numpy()[0])

    # 反向传播和优化
    optimizer.clear_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 100 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')

# 绘制训练损失曲线
plt.plot(range(num_epochs), losses)
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Training Loss')
plt.show()

# 模型评估
with paddle.no_grad():
    y_pred = model(X).numpy()

mse = mean_squared_error(y.numpy(), y_pred)
r2 = r2_score(y.numpy(), y_pred)
print(f"均方误差 (MSE): {mse}")
print(f"决定系数 (R²): {r2}")

# 输出模型的系数和截距
weights = model.linear.weight.numpy()[0][0]
bias = model.linear.bias.numpy()[0]
print(f"模型系数: {weights}")
print(f"模型截距: {bias}")

3. 训练和评估部分

  • 使用 train_losses 列表记录每一轮训练的损失值,方便后续绘制训练损失曲线,直观观察模型的训练过程。
  • 将数据集按 80:20 的比例划分为训练集和测试集,以更准确地评估模型的泛化能力。
  • 使用 scikit-learn 中的 mean_squared_error 和 r2_score 计算测试集的均方误差和决定系数。

二、保存paddlepaddle框架逻辑回归模型

以下将分别详细介绍使用 PaddlePaddle 框架通过基础 API、fit 方法以及 paddle.Model 类这三种方式来保存模型,同时会给出完整的代码示例和相应的解释。

方式 1:基础 API 保存

基础 API 保存主要是保存模型的参数(state_dict),也可以保存检查点信息。下面是一个逻辑回归模型的完整示例:

import paddle
import paddle.nn as nn
import numpy as np

# 自定义数据集
X = np.random.randn(1000, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)

X = paddle.to_tensor(X)
y = paddle.to_tensor(y)

# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)

# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
    outputs = model(X)
    loss = criterion(outputs, y)

    optimizer.clear_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')

# 保存模型的参数
paddle.save(model.state_dict(), './基础API/model.pdparams')

# 保存检查点信息
final_checkpoint = {
    'epoch': num_epochs,
    'model_state_dict': model.state_dict(),
    'optimizer_state_dict': optimizer.state_dict(),
    'loss': loss.numpy()[0]
}
paddle.save(final_checkpoint, "./基础API/final_checkpoint.pkl")

代码解释

  1. 数据与模型定义:生成自定义数据集,定义逻辑回归模型,并进行训练。
  2. 保存模型参数:使用 paddle.save(model.state_dict(), './基础API/model.pdparams') 保存模型的参数,这些参数可以在后续加载到相同结构的模型中。
  3. 保存检查点信息:创建一个包含训练轮数、模型参数、优化器状态和损失值的字典 final_checkpoint,使用 paddle.save 将其保存为 final_checkpoint.pkl 文件,方便后续恢复训练。

方式 2:训练 fit 进行保存

fit 方法是 PaddlePaddle 提供的一种方便的训练接口,在训练过程中可以设置保存模型的参数。

import paddle
import paddle.nn as nn
import numpy as np
from paddle.io import TensorDataset, DataLoader

# 自定义数据集
X = np.random.randn(1000, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)

X = paddle.to_tensor(X)
y = paddle.to_tensor(y)

# 创建数据集和数据加载器
dataset = TensorDataset([X, y])
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)

# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)

# 使用 fit 方法进行训练并保存模型
paddle.Model(model).fit(
    dataloader,
    epochs=100,
    optimizer=optimizer,
    loss=criterion,
    save_dir='./fit保存模型',
    save_freq=10
)

代码解释

  1. 数据处理:将自定义数据集封装成 TensorDataset,并使用 DataLoader 进行批量加载。
  2. 模型定义与配置:定义逻辑回归模型,设置损失函数和优化器。
  3. 使用 fit 方法训练并保存:使用 paddle.Model(model).fit 方法进行训练,save_dir 参数指定保存模型的目录,save_freq 参数指定每多少个轮次保存一次模型。

方式 3:利用 paddle.Model 类进行保存

paddle.Model 类提供了更高级的封装,方便进行模型的训练、评估和保存。

import paddle
import paddle.nn as nn
import numpy as np
from paddle.io import TensorDataset, DataLoader

# 自定义数据集
X = np.random.randn(1000, 2).astype(np.float32)
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)

X = paddle.to_tensor(X)
y = paddle.to_tensor(y)

# 创建数据集和数据加载器
dataset = TensorDataset([X, y])
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)

# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)

# 创建 paddle.Model 实例
paddle_model = paddle.Model(model)
paddle_model.prepare(optimizer, criterion)

# 训练模型
paddle_model.fit(dataloader, epochs=100)

# 保存模型
paddle_model.save('./paddle_Model保存模型/final_model')

代码解释

  1. 数据处理:同方式 2,将数据集封装成 TensorDataset 并使用 DataLoader 加载。
  2. 模型定义与配置:定义逻辑回归模型,设置损失函数和优化器。
  3. 创建 paddle.Model 实例:使用 paddle.Model(model) 创建实例,并使用 prepare 方法配置优化器和损失函数。
  4. 训练并保存模型:使用 fit 方法进行训练,训练完成后使用 paddle_model.save 保存模型。

通过以上三种方式,可以根据实际的需求选择合适的方法来保存 PaddlePaddle 模型。

三、加载paddlepaddle框架逻辑回归模型

以下为PaddlePaddle 中使用基础 API 和高级 API 加载模型的具体方法,将结合前面保存模型的示例,给出完整的代码实现和解释。

方式 1:基础 API 模型的加载

当使用基础 API 保存模型参数和检查点信息后,可按如下步骤加载:

import paddle
import paddle.nn as nn
import numpy as np

# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义优化器
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)

# 加载模型参数
model_state_dict = paddle.load('./基础API/model.pdparams')
# 加载优化器状态(如果之前保存了)
# 这里假设之前保存了优化器状态到 optimizer.pdopt 文件
optimizer_state_dict = paddle.load('./基础API/optimizer.pdopt')
# 加载检查点信息
final_checkpoint_state_dict = paddle.load('./基础API/final_checkpoint.pkl')

print(final_checkpoint_state_dict)

# 将模型和参数联系起来
model.set_state_dict(model_state_dict)
# 恢复优化器状态(如果需要)
optimizer.set_state_dict(optimizer_state_dict)

# 生成新数据进行预测
new_X = np.random.randn(100, 2).astype(np.float32)
new_X = paddle.to_tensor(new_X)

# 使用加载的模型进行预测
model.eval()
with paddle.no_grad():
    predictions = model(new_X)
    predicted_labels = (predictions >= 0.5).astype(paddle.float32).numpy()

print("预测标签:", predicted_labels)

代码解释

  1. 模型定义与初始化:定义逻辑回归模型并初始化。
  2. 加载参数与状态
    • paddle.load('./基础API/model.pdparams'):加载模型的参数。
    • paddle.load('./基础API/optimizer.pdopt'):加载优化器的状态(如果之前保存了)。
    • paddle.load('./基础API/final_checkpoint.pkl'):加载检查点信息。
  3. 参数关联
    • model.set_state_dict(model_state_dict):将加载的模型参数应用到模型上。
    • optimizer.set_state_dict(optimizer_state_dict):恢复优化器的状态(如果需要继续训练)。
  4. 模型预测:生成新数据,将模型设置为评估模式,进行预测并输出结果。

方式 2:高级 API 加载

使用 paddle.Model 封装模型并保存后,可按如下步骤加载:

import paddle
import paddle.nn as nn
import numpy as np
from paddle.io import TensorDataset, DataLoader

# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 使用 paddle.Model 进行封装
paddle_model = paddle.Model(model)

# 准备模型
paddle_model.prepare(optimizer=paddle.optimizer.SGD(learning_rate=0.01, parameters=model.parameters()),
                     loss=nn.BCELoss(),
                     metrics=paddle.metric.Accuracy())

# 高级 API 模型的加载
paddle_model.load("./高层API1/final")

# 生成新数据进行预测
new_X = np.random.randn(100, 2).astype(np.float32)
new_y = (2 * new_X[:, 0] + 3 * new_X[:, 1] > 0).astype(np.float32).reshape(-1, 1)
new_X = paddle.to_tensor(new_X)
new_y = paddle.to_tensor(new_y)

# 创建数据集和数据加载器
new_dataset = TensorDataset([new_X, new_y])
new_dataloader = DataLoader(new_dataset, batch_size=32, shuffle=False)

# 评估模型
result = paddle_model.evaluate(new_dataloader, verbose=1)
print("评估结果:", result)

代码解释

  1. 模型定义与封装:定义逻辑回归模型,使用 paddle.Model(model) 进行封装。
  2. 模型准备:使用 prepare 方法配置优化器、损失函数和评估指标。
  3. 加载模型:使用 paddle_model.load("./高层API1/final") 加载之前保存的模型。
  4. 数据准备:生成新数据,封装成 TensorDataset 并使用 DataLoader 加载。
  5. 模型评估:使用 paddle_model.evaluate 对加载的模型进行评估,并输出评估结果。

通过以上两种方式,可以根据之前保存模型的方式,选择合适的方法加载 PaddlePaddle 模型。

四、完整流程(使用类的方式 class nn.Layer 组网,且仅使用基础 API 保存与加载)

1. 实现思路

① 自定义数据集

生成符合特定分布的特征矩阵和对应的标签向量。

② 构建逻辑回归模型

定义一个简单的逻辑回归模型,这里使用类的方式 class nn.Layer 组网。

③ 训练模型

使用生成的数据集对模型进行训练。

④ 保存模型

将训练好的模型保存到本地文件。

⑤ 加载模型

从本地文件中加载保存的模型。

⑥ 模型预测

使用加载的模型对新数据进行预测。

2. 代码示例

import paddle
import paddle.nn as nn
import numpy as np
from sklearn.metrics import accuracy_score

# 自定义数据集
# 生成 1000 个样本,每个样本有 2 个特征
X = np.random.randn(1000, 2).astype(np.float32)
# 根据特征生成标签
y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1)

# 将 numpy 数组转换为 PaddlePaddle 张量
X = paddle.to_tensor(X)
y = paddle.to_tensor(y)

# 定义逻辑回归模型
class LogisticRegression(nn.Layer):
    def __init__(self, input_size):
        super(LogisticRegression, self).__init__()
        self.linear = nn.Linear(input_size, 1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        out = self.linear(x)
        out = self.sigmoid(out)
        return out

# 初始化模型
input_size = 2
model = LogisticRegression(input_size)

# 定义损失函数和优化器
criterion = nn.BCELoss()  # 二元交叉熵损失函数
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01)

# 训练模型
num_epochs = 100
for epoch in range(num_epochs):
    # 前向传播
    outputs = model(X)
    loss = criterion(outputs, y)

    # 反向传播和优化
    optimizer.clear_grad()
    loss.backward()
    optimizer.step()

    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.numpy()[0]:.4f}')

# 保存模型
paddle.save(model.state_dict(), 'logistic_regression_model.pdparams')

# 加载模型
loaded_model = LogisticRegression(input_size)
loaded_model.set_state_dict(paddle.load('logistic_regression_model.pdparams'))
loaded_model.eval()

# 生成新数据进行预测
new_X = np.random.randn(100, 2).astype(np.float32)
new_X = paddle.to_tensor(new_X)

# 使用加载的模型进行预测
with paddle.no_grad():
    predictions = loaded_model(new_X)
    predicted_labels = (predictions >= 0.5).astype(paddle.float32).numpy()

# 生成新数据对应的真实标签
true_labels = (2 * new_X.numpy()[:, 0] + 3 * new_X.numpy()[:, 1] > 0).astype(np.float32).reshape(-1, 1)

# 计算准确率
accuracy = accuracy_score(true_labels, predicted_labels)
print(f"预测准确率: {accuracy}")

3. 代码解释

① 数据集生成

  • X = np.random.randn(1000, 2).astype(np.float32):生成 1000 个样本,每个样本有 2 个特征。
  • y = (2 * X[:, 0] + 3 * X[:, 1] > 0).astype(np.float32).reshape(-1, 1):根据特征的线性组合生成标签,大于 0 标记为 1,否则标记为 0。
  • X = paddle.to_tensor(X) 和 y = paddle.to_tensor(y):将 numpy 数组转换为 PaddlePaddle 张量。

② 模型定义

  • LogisticRegression 类继承自 nn.Layer,包含一个线性层 nn.Linear 和一个 Sigmoid 激活函数 nn.Sigmoid
  • forward 方法定义了前向传播的逻辑。

③ 损失函数和优化器

  • criterion = nn.BCELoss():使用二元交叉熵损失函数,适用于二分类问题。
  • optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.01):使用 Adam 优化器,学习率为 0.01。

④ 模型训练

  • 通过多次迭代进行前向传播、损失计算、反向传播和参数更新。
  • 每 10 个 epoch 打印一次损失值。

⑤ 模型保存

  • paddle.save(model.state_dict(), 'logistic_regression_model.pdparams'):保存模型的参数到本地文件 logistic_regression_model.pdparams

⑥ 模型加载和预测

  1. loaded_model = LogisticRegression(input_size):创建一个新的模型实例。
  2. loaded_model.set_state_dict(paddle.load('logistic_regression_model.pdparams')):加载保存的模型参数。
  3. loaded_model.eval():将模型设置为评估模式。
  4. 生成新数据 new_X 并转换为张量。
  5. 使用 loaded_model 进行预测,通过 (predictions >= 0.5).astype(paddle.float32).numpy() 将预测概率转换为标签。

⑦ 准确率计算

  • 生成新数据对应的真实标签 true_labels
  • 使用 accuracy_score 计算预测准确率。

http://www.kler.cn/a/522040.html

相关文章:

  • [权限提升] 常见提权的环境介绍
  • 复古壁纸中棕色系和米色系哪个更受欢迎?
  • OpenHarmony 5.0.2 Release来了!
  • MySQL分表自动化创建的实现方案(存储过程、事件调度器)
  • Vue 3 + TypeScript 实现父子组件协同工作案例解析
  • 漏洞修复:Apache Tomcat 安全漏洞(CVE-2024-50379) | Apache Tomcat 安全漏洞(CVE-2024-52318)
  • Dismissible组件的用法
  • 【搜索回溯算法】:BFS的魔力--如何使用广度优先搜索找到最短路径
  • WPF进阶 | WPF 数据绑定进阶:绑定模式、转换器与验证
  • 病理AI领域基础模型及多实例学习方法的性能评估|顶刊精析·25-01-27
  • 算法刷题Day29:BM67 不同路径的数目(一)
  • 前端性能优化指标 - DCL - 计算 DCL 时间(使用 JavaScript、使用 Chrome DevTools)
  • LeetCode讲解篇之88. 合并两个有序数组
  • C语言算法实现:探索经典排序与查找算法的奥秘
  • 在亚马逊云科技上用Stable Diffusion 3.5 Large生成赛博朋克风图片(下)
  • Day27-【13003】短文,线性表两种基本实现方式空间效率、时间效率比较?兼顾优点的静态链表是什么?如何融入空闲单元链表来解决问题?
  • 二分查找题目:寻找两个正序数组的中位数
  • Maya快捷键
  • 遗传算法与深度学习实战(32)——生成对抗网络详解与实现
  • Python dataclasses模块介绍
  • UE学习日志#13 (还是记录看资料,没内容)GAS--理解GC和UE网络同步原理
  • 格式化指南:格式化选NTFS、FAT32还是 exFAT?
  • 28. 【.NET 8 实战--孢子记账--从单体到微服务】--简易报表--报表定时器与报表数据修正
  • DeepSeek学术写作测评第一弹:论文润色,中译英效果如何?
  • 【算法篇·更新中】C++秒入门(附练习用题目)
  • 【C语言基础】编译并运行第一个C程序