<think>好的,我现在需要帮用户解决一个关于梯度下降算法和交叉熵损失的代码示例的问题。首先,用户之前遇到了Matplotlib的字体和显示问题,我之前已经给出了解决方案,现在他们可能在进行机器学习相关的实践,特别是分类任务。用户要求一个完整的代码示例,演示梯度下降算法并使用交叉熵损失。我需要确保这个示例既清晰又正确,同时符合用户的需求。
首先,我要确定用户的使用场景。他们可能是在学习机器学习的基础知识,特别是逻辑回归或分类模型。梯度下降是优化这些模型的关键算法,而交叉熵损失常用于分类问题。用户可能需要一个从数据生成到模型训练、结果可视化的完整流程,这样他们可以直观地理解整个过程。
接下来,我需要考虑用户的真实需求。用户可能希望代码示例包含数据准备、模型定义、损失函数(交叉熵)、梯度下降的实现、训练循环以及结果的可视化。此外,用户之前遇到的Matplotlib问题提示我需要确保代码中的可视化部分不会再次出现字体或显示问题,所以应该在代码中预先设置中文字体,并可能建议保存图像而不是直接显示。
然后,我需要确保代码的正确性。例如,逻辑回归中使用交叉熵损失,梯度下降的更新步骤是否正确,学习率和迭代次数的选择是否合理。数据生成部分可能需要使用合成数据,比如通过make_classification生成二分类数据集,并划分训练集和测试集。
另外,考虑到用户可能在不同的环境中运行代码,比如Jupyter笔记本或无图形界面的服务器,所以在可视化部分应该包含保存图像到文件的代码,而不是依赖交互式显示。同时,设置Matplotlib的字体,避免中文字符缺失的警告,这需要添加相关的配置代码。
在编写代码时,需要注意以下几点:数据标准化,这对梯度下降的收敛很重要;参数初始化,比如权重和偏置初始化为零或小随机数;计算损失和梯度的正确性,特别是交叉熵损失对参数的导数;以及训练过程中损失和准确率的跟踪,方便后续分析模型性能。
可能还需要解释代码的关键部分,帮助用户理解每个步骤的作用。例如,sigmoid函数将线性输出转换为概率,交叉熵损失的计算公式,梯度计算的过程,以及参数更新的步骤。同时,可视化部分需要展示决策边界,这可以通过网格预测和等高线绘制来实现,帮助用户直观看到分类效果。
最后,我需要验证代码是否能够正常运行,并且没有错误。例如,检查矩阵乘法的维度是否正确,梯度计算是否与损失函数匹配,学习率是否合适以避免梯度爆炸或收敛过慢。此外,确保所有库都已正确导入,并且版本兼容,比如使用numpy进行数值计算,matplotlib进行绘图,sklearn生成数据集和评估指标。
总结来说,我需要提供一个结构清晰、注释详细、包含必要错误处理的代码示例,同时考虑到用户之前的环境问题,确保可视化部分不会报错,并且解释每个步骤的原理,帮助用户深入理解梯度下降和交叉熵在分类任务中的应用。</think>以下是一个**完整代码示例**,演示如何使用梯度下降算法和交叉熵损失实现逻辑回归分类任务。代码包含数据生成、模型训练和可视化分析:
---
### **代码实现**
```python
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
# 1. 配置中文字体 (解决之前用户遇到的警告)
plt.rcParams["font.family"] = "SimHei"
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 2. 生成二分类数据集
X, y = make_classification(n_samples=1000, n_features=2, n_informative=2,
n_redundant=0, n_clusters_per_class=1, random_state=42)
X = (X - X.mean(axis=0)) / X.std(axis=0) # 数据标准化
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 3. 定义模型和参数
class LogisticRegression:
def __init__(self, lr=0.01, n_iters=1000):
self.lr = lr # 学习率
self.n_iters = n_iters # 迭代次数
self.weights = None # 权重
self.bias = None # 偏置项
# Sigmoid激活函数
def _sigmoid(self, z):
return 1 / (1 + np.exp(-z))
# 交叉熵损失函数
def _cross_entropy(self, y, y_pred):
return -np.mean(y * np.log(y_pred) + (1 - y) * np.log(1 - y_pred))
def fit(self, X, y):
n_samples, n_features = X.shape
self.weights = np.zeros(n_features) # 初始化权重
self.bias = 0 # 初始化偏置
# 梯度下降优化
self.loss_history = []
for _ in range(self.n_iters):
# 前向传播
linear = np.dot(X, self.weights) + self.bias
y_pred = self._sigmoid(linear)
# 计算损失
loss = self._cross_entropy(y, y_pred)
self.loss_history.append(loss)
# 反向传播 (计算梯度)
dw = (1/n_samples) * np.dot(X.T, (y_pred - y)) # 权重梯度
db = (1/n_samples) * np.sum(y_pred - y) # 偏置梯度
# 参数更新
self.weights -= self.lr * dw
self.bias -= self.lr * db
def predict(self, X):
linear = np.dot(X, self.weights) + self.bias
y_pred = self._sigmoid(linear)
return (y_pred > 0.5).astype(int)
# 4. 训练模型
model = LogisticRegression(lr=0.1, n_iters=2000)
model.fit(X_train, y_train)
# 5. 评估模型
y_pred = model.predict(X_test)
print(f"测试集准确率: {accuracy_score(y_test, y_pred):.4f}")
# 6. 可视化结果
plt.figure(figsize=(12, 5))
# 损失曲线
plt.subplot(1, 2, 1)
plt.plot(model.loss_history)
plt.title("交叉熵损失变化曲线")
plt.xlabel("迭代次数")
plt.ylabel("损失值")
# 决策边界
plt.subplot(1, 2, 2)
x1_min, x1_max = X[:, 0].min()-0.5, X[:, 0].max()+0.5
x2_min, x2_max = X[:, 1].min()-0.5, X[:, 1].max()+0.5
xx1, xx2 = np.meshgrid(np.linspace(x1_min, x1_max, 100),
np.linspace(x2_min, x2_max, 100))
Z = model.predict(np.c_[xx1.ravel(), xx2.ravel()]).reshape(xx1.shape)
plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=plt.cm.Paired)
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', cmap=plt.cm.Paired)
plt.title("分类决策边界")
plt.xlabel("特征1")
plt.ylabel("特征2")
plt.tight_layout()
plt.savefig("logistic_regression_result.png") # 保存图像避免显示问题
```
---
### **关键代码解析**
1. **数据预处理**:
- 使用 `make_classification` 生成合成数据
- 标准化数据加速梯度下降收敛
- 划分训练集和测试集
2. **梯度下降核心步骤**:
- **前向传播**:计算线性组合 $z = w^Tx + b$ 和预测概率 $\sigma(z) = \frac{1}{1+e^{-z}}$
- **交叉熵损失**:$L = -\frac{1}{N}\sum_{i=1}^N [y_i\log(\sigma(z_i)) + (1-y_i)\log(1-\sigma(z_i))]$
- **梯度计算**:
- $\frac{\partial L}{\partial w} = \frac{1}{N}X^T(\sigma(z)-y)$
- $\frac{\partial L}{\partial b} = \frac{1}{N}\sum(\sigma(z)-y)$
- **参数更新**:$w = w - \eta \frac{\partial L}{\partial w}$,$b = b - \eta \frac{\partial L}{\partial b}$
3. **可视化设计**:
- 损失曲线展示训练过程
- 决策边界显示分类效果
- 保存图像避免交互式显示问题
---
### **运行结果示例**
```
测试集准确率: 0.9450
```

---
### **超参数调优建议**
1. **学习率选择**:
- 尝试 0.1, 0.01, 0.001 等不同值
- 观察损失曲线是否平稳下降
2. **迭代次数优化**:
- 当损失值不再明显下降时停止训练
- 可使用早停法 (Early Stopping)
3. **正则化扩展**:
- 在损失函数中加入 L2 正则项:
$$L = L_{CE} + \lambda \|w\|^2$$
- 对应梯度更新:$w = w - \eta (\frac{\partial L}{\partial w} + 2\lambda w)$
---
### **扩展对比**
| **优化算法** | **特点** | **适用场景** |
|------------------|-----------------------------------|---------------------------|
| 批量梯度下降 | 每次使用全量数据计算梯度 | 小数据集 (<1万样本) |
| 随机梯度下降 (SGD)| 每次随机选取单个样本更新 | 大数据集,快速收敛 |
| 小批量梯度下降 | 平衡计算效率和收敛稳定性 | 大多数场景的默认选择 |
该代码展示了机器学习模型的核心实现逻辑,可根据具体需求扩展为更复杂的神经网络模型。