Upload README.md
This commit is contained in:
603
README.md
603
README.md
@@ -1,3 +1,602 @@
|
|||||||
# task-3-2-2-text-classification
|
# 文本分类实战 - 课堂讲义
|
||||||
|
|
||||||
文本分类实战 - 纯NumPy实现
|
> 本项目用**纯NumPy**实现文本分类,帮助学生理解文本向量化和神经网络的基本原理。
|
||||||
|
>
|
||||||
|
> 类比:MNIST(图像)→ 全连接网络 → 数字分类,本项目是文本版。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 目录
|
||||||
|
|
||||||
|
1. [实验概述](#1-实验概述)
|
||||||
|
2. [数据预处理:如何让计算机"读懂"文本](#2-数据预处理如何让计算机读懂文本)
|
||||||
|
3. [向量化方法:BoW 与 TF-IDF](#3-向量化方法bow-与-tf-idf)
|
||||||
|
4. [模型一:逻辑回归(Logistic Regression)](#4-模型一逻辑回归logistic-regression)
|
||||||
|
5. [模型二:多层感知机(MLP)](#5-模型二多层感知机mlp)
|
||||||
|
6. [训练过程:梯度下降与反向传播](#6-训练过程梯度下降与反向传播)
|
||||||
|
7. [数据不平衡问题与解决](#7-数据不平衡问题与解决)
|
||||||
|
8. [实验操作指南](#8-实验操作指南)
|
||||||
|
9. [预测新文本](#9-预测新文本)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 实验概述
|
||||||
|
|
||||||
|
### 1.1 任务
|
||||||
|
|
||||||
|
对中文酒店评论进行**情感分类**:
|
||||||
|
- 正面评论(好评)
|
||||||
|
- 负面评论(差评)
|
||||||
|
|
||||||
|
### 1.2 数据集
|
||||||
|
|
||||||
|
**ChnSentiCorp**(中文酒店评论数据集)
|
||||||
|
- 总评论数:7765条
|
||||||
|
- 正面评论:5322条(68.5%)
|
||||||
|
- 负面评论:2443条(31.5%)
|
||||||
|
|
||||||
|
数据集已内置,程序会自动下载。
|
||||||
|
|
||||||
|
### 1.3 整体流程
|
||||||
|
|
||||||
|
```
|
||||||
|
原始文本 → 分词 → 向量化 → 模型训练 → 预测
|
||||||
|
"酒店很好" → ["酒店", "很好"] → [0.3, 0.8, ...] → 正面
|
||||||
|
```
|
||||||
|
|
||||||
|
### 1.4 代码文件
|
||||||
|
|
||||||
|
| 文件 | 作用 |
|
||||||
|
|-----|------|
|
||||||
|
| `config.py` | 所有超参数配置(改这里来调整实验) |
|
||||||
|
| `dataset.py` | 数据加载、分词、向量化 |
|
||||||
|
| `model_numpy.py` | 逻辑回归和MLP模型实现 |
|
||||||
|
| `train.py` | 训练和对比实验 |
|
||||||
|
| `predict.py` | 加载模型预测新文本 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 数据预处理:如何让计算机"读懂"文本
|
||||||
|
|
||||||
|
### 2.1 为什么文本不能直接用于计算?
|
||||||
|
|
||||||
|
计算机只能处理数字,不能直接处理文字。我们需要把文本转换成数字向量。
|
||||||
|
|
||||||
|
### 2.2 分词
|
||||||
|
|
||||||
|
**原理**:把连续的中文文本切成离散的词。
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 示例
|
||||||
|
文本: "酒店服务很好"
|
||||||
|
分词: ["酒店", "服务", "很好"]
|
||||||
|
```
|
||||||
|
|
||||||
|
本项目使用 `jieba` 库进行分词:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import jieba
|
||||||
|
|
||||||
|
text = "酒店服务很好"
|
||||||
|
words = jieba.lcut(text)
|
||||||
|
print(words) # ['酒店', '服务', '很好']
|
||||||
|
```
|
||||||
|
|
||||||
|
**注意**:过滤掉单字(如"的"、"了"),因为信息量太少。
|
||||||
|
|
||||||
|
```python
|
||||||
|
words = [w for w in words if len(w) > 1] # 过滤单字
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.3 构建词表
|
||||||
|
|
||||||
|
**原理**:把所有评论中的词收集起来,编上序号。
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 词表示例
|
||||||
|
{
|
||||||
|
"酒店": 0,
|
||||||
|
"服务": 1,
|
||||||
|
"很好": 2,
|
||||||
|
"房间": 3,
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
词表大小由 `MAX_FEATURES` 控制(本项目设为3000),只保留出现频率最高的3000个词。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 向量化方法:BoW 与 TF-IDF
|
||||||
|
|
||||||
|
把分词后的文本转换成数字向量。
|
||||||
|
|
||||||
|
### 3.1 BoW(词袋模型)
|
||||||
|
|
||||||
|
**原理**:统计每个词出现的次数。
|
||||||
|
|
||||||
|
```
|
||||||
|
文本: "酒店 服务 很好 服务"
|
||||||
|
分词: ["酒店", "服务", "很好", "服务"]
|
||||||
|
词表: {"酒店":0, "服务":1, "很好":2, "不错":3, ...}
|
||||||
|
|
||||||
|
向量: [1, 2, 1, 0, ...] # 酒店出现1次,服务出现2次,很好出现1次
|
||||||
|
```
|
||||||
|
|
||||||
|
**代码位置**:`dataset.py` 中的 `BoWVectorizer` 类
|
||||||
|
|
||||||
|
```python
|
||||||
|
class BoWVectorizer:
|
||||||
|
def transform(self, text):
|
||||||
|
words = tokenize(text)
|
||||||
|
vec = [0] * MAX_SEQ_LEN
|
||||||
|
for i, word in enumerate(words[:MAX_SEQ_LEN]):
|
||||||
|
if word in self.vocab:
|
||||||
|
vec[i] = 1 # 也可以用词频 tf[word]
|
||||||
|
return vec
|
||||||
|
```
|
||||||
|
|
||||||
|
**问题**:所有词权重相同,导致常见词(如"的"、"是")主导。
|
||||||
|
|
||||||
|
### 3.2 TF-IDF(词频-逆文档频率)
|
||||||
|
|
||||||
|
**原理**:给每个词赋予重要程度权重。
|
||||||
|
|
||||||
|
```
|
||||||
|
TF(词频) = 词在本文中出现的次数
|
||||||
|
IDF(逆文档频率) = log(总文档数 / 包含该词的文档数)
|
||||||
|
|
||||||
|
TF-IDF = TF × IDF
|
||||||
|
```
|
||||||
|
|
||||||
|
**直观理解**:
|
||||||
|
- 一个词在本文中出现越多 → TF越高 → 越重要
|
||||||
|
- 一个词在所有文档中越常见 → IDF越低 → 越不重要
|
||||||
|
|
||||||
|
```
|
||||||
|
例子:
|
||||||
|
- "酒店":在100篇评论中出现80篇 → IDF = log(100/80) ≈ 0.22
|
||||||
|
- "惊喜":在100篇评论中出现5篇 → IDF = log(100/5) ≈ 3.0
|
||||||
|
|
||||||
|
"惊喜"虽然少见,但信息量大,IDF更高
|
||||||
|
```
|
||||||
|
|
||||||
|
**代码位置**:`dataset.py` 中的 `TFIDFVectorizer` 类
|
||||||
|
|
||||||
|
```python
|
||||||
|
class TFIDFVectorizer:
|
||||||
|
def transform(self, text):
|
||||||
|
words = tokenize(text)
|
||||||
|
tf = Counter(words) # 词频
|
||||||
|
tf_sum = len(words)
|
||||||
|
|
||||||
|
vec = [0.0] * MAX_SEQ_LEN
|
||||||
|
for i, word in enumerate(words[:MAX_SEQ_LEN]):
|
||||||
|
if word in self.vocab:
|
||||||
|
# TF × IDF
|
||||||
|
vec[i] = (tf[word] / tf_sum) * self.idf.get(word, 0)
|
||||||
|
return vec
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 两种方法对比
|
||||||
|
|
||||||
|
| 特性 | BoW | TF-IDF |
|
||||||
|
|-----|-----|--------|
|
||||||
|
| 公式 | 词频 | TF × IDF |
|
||||||
|
| 常见词权重 | 相同(偏高) | 降低 |
|
||||||
|
| 罕见词权重 | 相同(偏低) | 提升 |
|
||||||
|
| 计算复杂度 | 低 | 稍高 |
|
||||||
|
| 效果 | 一般 | 通常更好 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 模型一:逻辑回归(Logistic Regression)
|
||||||
|
|
||||||
|
### 4.1 模型结构
|
||||||
|
|
||||||
|
最简单的线性分类器:
|
||||||
|
|
||||||
|
```
|
||||||
|
输入 [batch, features]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
线性变换: Z = X @ W + b
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Softmax → 概率
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
输出 [batch, 2] # [负面概率, 正面概率]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.2 线性变换
|
||||||
|
|
||||||
|
```python
|
||||||
|
Z = X @ W + b
|
||||||
|
|
||||||
|
# 例子:
|
||||||
|
# X: [1, 3000] (一个样本,3000维特征)
|
||||||
|
# W: [3000, 2] (权重矩阵)
|
||||||
|
# b: [2] (偏置)
|
||||||
|
# Z: [1, 2] (输出 logits)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.3 Softmax
|
||||||
|
|
||||||
|
把 logits 转换成概率(和为1):
|
||||||
|
|
||||||
|
```python
|
||||||
|
def softmax(x):
|
||||||
|
exp_x = np.exp(x - np.max(x)) # 减最大值防溢出
|
||||||
|
return exp_x / np.sum(exp_x, axis=1, keepdims=True)
|
||||||
|
|
||||||
|
# 示例
|
||||||
|
logits = [2.0, 1.0]
|
||||||
|
probs = softmax(logits)
|
||||||
|
# probs = [0.731, 0.269]
|
||||||
|
# 解释:正面概率73.1%,负面概率26.9%
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.4 代码实现
|
||||||
|
|
||||||
|
```python
|
||||||
|
class LogisticRegression:
|
||||||
|
def __init__(self, input_size, num_classes=2):
|
||||||
|
self.W = np.random.randn(input_size, num_classes) * 0.01
|
||||||
|
self.b = np.zeros(num_classes)
|
||||||
|
|
||||||
|
def forward(self, X):
|
||||||
|
z = X @ self.W + self.b
|
||||||
|
return softmax(z)
|
||||||
|
|
||||||
|
def backward(self, X, y):
|
||||||
|
# 梯度计算和参数更新
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4.5 参数量
|
||||||
|
|
||||||
|
```
|
||||||
|
W: input_size × num_classes = 3000 × 2 = 6000
|
||||||
|
b: num_classes = 2
|
||||||
|
总计: 6002
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 模型二:多层感知机(MLP)
|
||||||
|
|
||||||
|
### 5.1 模型结构
|
||||||
|
|
||||||
|
比逻辑回归多了一层隐藏层和非线性激活:
|
||||||
|
|
||||||
|
```
|
||||||
|
输入 [batch, features]
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
线性变换: Z1 = X @ W1 + b1
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
ReLU激活: A1 = max(0, Z1)
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
线性变换: Z2 = A1 @ W2 + b2
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
Softmax → 概率
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
输出 [batch, 2]
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.2 ReLU激活函数
|
||||||
|
|
||||||
|
```python
|
||||||
|
def relu(x):
|
||||||
|
return np.maximum(0, x)
|
||||||
|
|
||||||
|
# 示例
|
||||||
|
relu([1, -2, 3, -1]) = [1, 0, 3, 0]
|
||||||
|
```
|
||||||
|
|
||||||
|
**作用**:引入非线性,让模型能学习复杂模式。
|
||||||
|
|
||||||
|
### 5.3 参数量
|
||||||
|
|
||||||
|
```
|
||||||
|
W1: input_size × hidden = 3000 × 64 = 192000
|
||||||
|
b1: hidden = 64
|
||||||
|
W2: hidden × num_classes = 64 × 2 = 128
|
||||||
|
b2: num_classes = 2
|
||||||
|
总计: 192194
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5.4 与视觉CNN的类比
|
||||||
|
|
||||||
|
| 视觉(全连接) | 文本 |
|
||||||
|
|--------------|------|
|
||||||
|
| 输入: 784维像素 | 输入: 3000维词向量 |
|
||||||
|
| 隐藏层: 128神经元 | 隐藏层: 64神经元 |
|
||||||
|
| 输出: 10类数字 | 输出: 2类情感 |
|
||||||
|
| ReLU + Softmax | ReLU + Softmax |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 训练过程:梯度下降与反向传播
|
||||||
|
|
||||||
|
### 6.1 训练流程
|
||||||
|
|
||||||
|
```
|
||||||
|
for epoch in 轮数:
|
||||||
|
for batch in 数据:
|
||||||
|
1. 前向传播: 计算输出概率
|
||||||
|
2. 计算损失: CrossEntropy(probs, labels)
|
||||||
|
3. 反向传播: 计算梯度
|
||||||
|
4. 更新参数: W = W - lr × 梯度
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.2 损失函数:交叉熵
|
||||||
|
|
||||||
|
```python
|
||||||
|
def cross_entropy_loss(probs, y):
|
||||||
|
# probs: 预测概率
|
||||||
|
# y: 真实标签
|
||||||
|
loss = -np.log(probs[y]) # 正确类的概率越大,损失越小
|
||||||
|
return loss
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.3 梯度下降
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 简单示例:单参数
|
||||||
|
loss = f(w) # 损失是参数的函数
|
||||||
|
gradient = (loss(w + epsilon) - loss(w)) / epsilon # 数值梯度
|
||||||
|
|
||||||
|
# 解析梯度
|
||||||
|
w = w - learning_rate * gradient
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.4 反向传播(BP)
|
||||||
|
|
||||||
|
链式法则,从后往前计算梯度:
|
||||||
|
|
||||||
|
```
|
||||||
|
损失 → Softmax → 线性变换 → ReLU → 线性变换 → 输入
|
||||||
|
↓
|
||||||
|
链式求导
|
||||||
|
↓
|
||||||
|
各层梯度 = 损失对各层参数的偏导
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6.5 训练日志解读
|
||||||
|
|
||||||
|
```
|
||||||
|
Epoch 20/100 | Loss: 0.5844 | 训练准确率: 0.6851 | 测试准确率: 0.6864
|
||||||
|
│ │ │ │
|
||||||
|
│ │ │ └─ 测试集上的表现
|
||||||
|
│ │ └─ 训练集上的表现
|
||||||
|
│ └─ 损失值(越小越好)
|
||||||
|
└─ 当前轮数/总轮数
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 数据不平衡问题与解决
|
||||||
|
|
||||||
|
### 7.1 问题
|
||||||
|
|
||||||
|
本数据集正负比例约 7:3,模型可能"偷懒":
|
||||||
|
|
||||||
|
| 策略 | 结果 | 准确率 |
|
||||||
|
|-----|------|--------|
|
||||||
|
| 不使用技巧,总是预测正面 | 简单但无效 | 68.5%(假高分) |
|
||||||
|
| 使用类别权重,认真学习 | 难但有效 | 46%(真学习) |
|
||||||
|
|
||||||
|
### 7.2 类别权重
|
||||||
|
|
||||||
|
**原理**:给少数类更高的权重,让模型更"怕"漏判少数类。
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 计算权重
|
||||||
|
n_samples = 7765 # 总样本数
|
||||||
|
n_pos = 5322 # 正面样本数
|
||||||
|
n_neg = 2443 # 负面样本数
|
||||||
|
|
||||||
|
weight_pos = n_samples / (2 * n_pos) = 0.73 # 正面权重(样本多,权重小)
|
||||||
|
weight_neg = n_samples / (2 * n_neg) = 1.59 # 负面权重(样本少,权重大)
|
||||||
|
|
||||||
|
# 梯度更新时
|
||||||
|
d_z[y] -= class_weight[y] # 负面样本的梯度更大
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.3 开关配置
|
||||||
|
|
||||||
|
在 `config.py` 中:
|
||||||
|
|
||||||
|
```python
|
||||||
|
USE_CLASS_WEIGHT = True # 开启类别权重
|
||||||
|
USE_CLASS_WEIGHT = False # 关闭(总是预测正面)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7.4 实验对比
|
||||||
|
|
||||||
|
| 配置 | 测试准确率 | 预测分布 | 说明 |
|
||||||
|
|-----|----------|---------|------|
|
||||||
|
| 关闭权重 | 68.6% | 全预测正面 | 模型偷懒 |
|
||||||
|
| 开启权重 | 46.4% | 有正有负 | 模型在学习 |
|
||||||
|
|
||||||
|
**结论**:68%准确率是"假"高分,46%是"真"学习。数据不平衡问题没有银弹。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 实验操作指南
|
||||||
|
|
||||||
|
### 8.1 安装依赖
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pip install numpy jieba
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.2 训练模型
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.3 修改配置
|
||||||
|
|
||||||
|
编辑 `config.py`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# 选择模型
|
||||||
|
MODEL_TYPE = 'mlp' # 'lr' 或 'mlp'
|
||||||
|
VECTORIZER_TYPE = 'tfidf' # 'bow' 或 'tfidf'
|
||||||
|
|
||||||
|
# 开关类别权重
|
||||||
|
USE_CLASS_WEIGHT = True # 或 False
|
||||||
|
|
||||||
|
# 调整超参数
|
||||||
|
NUM_EPOCHS = 100 # 训练轮数
|
||||||
|
LEARNING_RATE = 0.05 # 学习率
|
||||||
|
HIDDEN_SIZE = 64 # MLP隐藏层大小
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.4 运行对比实验
|
||||||
|
|
||||||
|
```python
|
||||||
|
RUN_COMPARISON = True # 开启
|
||||||
|
```
|
||||||
|
|
||||||
|
会自动进行:
|
||||||
|
1. BoW vs TF-IDF 对比
|
||||||
|
2. LR vs MLP 对比
|
||||||
|
3. 学习率对比
|
||||||
|
4. 隐藏层大小对比
|
||||||
|
|
||||||
|
### 8.5 训练输出示例
|
||||||
|
|
||||||
|
```
|
||||||
|
============================================================
|
||||||
|
训练配置:
|
||||||
|
模型: MLP
|
||||||
|
向量: TF-IDF
|
||||||
|
学习率: 0.05
|
||||||
|
隐藏层大小: 64
|
||||||
|
训练轮数: 100
|
||||||
|
============================================================
|
||||||
|
类别权重: 正面=0.73, 负面=1.59
|
||||||
|
MLP: 100 -> 64 -> 2, 参数量: 6594
|
||||||
|
Epoch 20/100 | Loss: 0.6694 | 训练准确率: 0.4598 | 测试准确率: 0.4662
|
||||||
|
...
|
||||||
|
最终结果:
|
||||||
|
训练准确率: 0.4596
|
||||||
|
测试准确率: 0.4668
|
||||||
|
训练时间: 2.95秒
|
||||||
|
模型已保存: model_mlp_tfidf_weighted_0427_212802_*.npy
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 预测新文本
|
||||||
|
|
||||||
|
### 9.1 使用方法
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python predict.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.2 操作流程
|
||||||
|
|
||||||
|
```
|
||||||
|
1. 程序列出已保存的模型
|
||||||
|
2. 输入编号选择模型
|
||||||
|
3. 输入评论文本
|
||||||
|
4. 查看预测结果
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.3 示例
|
||||||
|
|
||||||
|
```
|
||||||
|
请选择模型编号 (1-1): 1
|
||||||
|
|
||||||
|
请输入评论文本: 酒店服务很好,环境也不错
|
||||||
|
预测结果: 正面
|
||||||
|
置信度: 99.7%
|
||||||
|
详细: 正面概率=99.7%, 负面概率=0.3%
|
||||||
|
|
||||||
|
请输入评论文本: 房间太小,卫生很差
|
||||||
|
预测结果: 负面
|
||||||
|
置信度: 85.2%
|
||||||
|
详细: 正面概率=14.8%, 负面概率=85.2%
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9.4 权重文件命名
|
||||||
|
|
||||||
|
每次训练生成唯一的文件名:
|
||||||
|
|
||||||
|
```
|
||||||
|
model_mlp_tfidf_weighted_0427_212802_W1.npy
|
||||||
|
model_mlp_tfidf_weighted_0427_212802_b1.npy
|
||||||
|
model_mlp_tfidf_weighted_0427_212802_W2.npy
|
||||||
|
model_mlp_tfidf_weighted_0427_212802_b2.npy
|
||||||
|
```
|
||||||
|
|
||||||
|
文件名包含:模型类型、向量类型、权重开关、时间戳
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. 思考题
|
||||||
|
|
||||||
|
1. **向量化**:为什么TF-IDF通常比BoW效果好?
|
||||||
|
2. **模型复杂度**:MLP比LR多了一层,带来的优势是什么?
|
||||||
|
3. **数据不平衡**:68%准确率一定好吗?有什么陷阱?
|
||||||
|
4. **类别权重**:开启后准确率反而下降,这说明什么?
|
||||||
|
5. **调参实践**:学习率过大会怎样?隐藏层太小会怎样?
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 附录:完整代码流程图
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────┐
|
||||||
|
│ config.py │
|
||||||
|
│ (超参数) │
|
||||||
|
└──────┬──────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ dataset.py │
|
||||||
|
│ ┌───────────┐ ┌──────────────────┐ │
|
||||||
|
│ │ 下载数据 │───▶│ TF-IDF/BoW向量化 │ │
|
||||||
|
│ └───────────┘ └────────┬─────────┘ │
|
||||||
|
│ │ │
|
||||||
|
└────────────────────────────┼────────────┘
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ 特征向量 X │
|
||||||
|
│ 标签 y │
|
||||||
|
└────────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ model_numpy.py │
|
||||||
|
│ ┌───────────────────────────────────┐ │
|
||||||
|
│ │ LogisticRegression / MLP │ │
|
||||||
|
│ │ - forward(): 前向传播 │ │
|
||||||
|
│ │ - backward(): 反向传播 │ │
|
||||||
|
│ │ - fit(): 训练循环 │ │
|
||||||
|
│ └───────────────────────────────────┘ │
|
||||||
|
└────────────────────────────┬────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ 保存权重 │
|
||||||
|
│ model_*.npy │
|
||||||
|
└────────┬───────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌────────────────┐
|
||||||
|
│ predict.py │
|
||||||
|
│ (加载预测) │
|
||||||
|
└───────────────┘
|
||||||
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user