更新了机器学习部分的文档
This commit is contained in:
parent
a1003a71a8
commit
7127780adf
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
人工智能无疑是最近几年热度极高的一个词,从2016年谷歌 DeepMind 团队开发的 AlphaGo 围棋程序战胜人类顶尖棋手,到2017年基于 Transformer 架构的 NLP 模型发布,再到2023年 OpenAI 推出基于 GPT-4 的 ChatGPT 以及人工智能在医疗、自动驾驶等领域的深度应用,人工智能的热潮到达了自1956年达特茅斯会议以来前所未有的高度,可以说几乎每个人的生活都或多或少的受到了人工智能的影响。人工智能是计算机科学的一个重要分支,涉及计算机模拟智能行为的能力以及机器模仿人类智能行为的能力。研究人工智能的主要目标是开发出能够独立做出决策的系统,从而在医疗、工程、金融、教育、科研、公共服务等诸多领域帮助人类更高效的工作。人工智能的英文是“*artificial intelligence*”,因此通常被简称为 *AI*,人工智能包含了诸多的内容,我们经常说到的机器学习、深度学习、自然语言处理、计算机视觉、强化学习、数据挖掘、专家系统、工业机器人、自动驾驶等都属于人工智能的范畴。狭义的人工智能通常只能执行特定的任务,会聊天的人工智能通常不会开车,会开车的人工智能通常不会下棋;广义的人工智能需要具备通用智能,能够执行任何人类智能可以执行的任务;而更进一步的能够超越人类智能的人工智能,我们称之为超人工智能。
|
||||
|
||||
本课程我们主要探讨人工智能中的机器学习(Machine Learning)。机器学习是人工智能的一个子领域,关注如何通过数据和算法来使计算机系统从经验中学习并进行预测或决策。简单的说,机器学习是实现人工智能的一种方法,有很多 AI 系统都是通过机器学习技术开发的。有的时候,我们也用数据挖掘(Data Mining)这个词来指代机器学习,所谓的数据挖掘就是从数据中提取有用的信息和知识,分析和解释数据中的模式和趋势,最终达成预测未来趋势和行为的目标。当然,我们在提到这两个词的时候,表达的侧重点还是有所区别,数据挖掘主要关注知识发现,而机器学习侧重于构建和优化预测模型。
|
||||
本课程我们主要探讨人工智能中的机器学习(Machine Learning)。机器学习是人工智能的一个子领域,关注如何通过数据和算法来使计算机系统从经验中学习并进行预测或决策。简单的说,机器学习是实现人工智能的一种方法,有很多 AI 系统都是通过机器学习技术开发的。在一些特定场景,人们也用数据挖掘(Data Mining)这个词来指代机器学习,所谓的数据挖掘就是从数据中提取有用的信息和知识,分析和解释数据中的模式和趋势,最终达成预测未来趋势和行为的目标。当然,我们在提到这两个词的时候,表达的侧重点还是有所区别,数据挖掘主要关注知识发现,而机器学习侧重于构建和优化预测模型。当下,还有一个非常热门的概念和研究领域叫深度学习(Deep Learning),它是机器学习的一个子领域,特别侧重于使用多层神经网络(深度神经网络)来进行数据处理和学习。深度学习在处理图像、语音和自然语言等复杂数据时表现出色,能够自动学习数据的层次化特征,从而降低人工干预的需求。当然,深度学习模型通常比传统的机器学习模型更复杂,且需要更多的数据和计算资源。
|
||||
|
||||
### 人工智能发展史
|
||||
|
||||
|
|
|
|||
|
|
@ -12,39 +12,39 @@ $$
|
|||
|
||||
其中, $\small{p \ge 1}$ ,虽然 $\small{p \lt 1}$ 可以计算,但不再严格满足距离的定义,通常不被视为真正的距离。
|
||||
|
||||
当 $\small{p = 1}$ 时,闵氏距离退化为**曼哈顿距离**,即:
|
||||
当 $\small{p = 1}$ 时,闵氏距离即**曼哈顿距离**:
|
||||
|
||||
$$
|
||||
d(\mathbf{x}, \mathbf{y}) = \sum_{i=1}^{n} \lvert x_{i} - y_{i} \rvert
|
||||
$$
|
||||
|
||||
当 $\small{p = 2}$ 时,闵氏距离退化为**欧几里得距离**,即:
|
||||
当 $\small{p = 2}$ 时,闵氏距离即**欧几里得距离**:
|
||||
|
||||
$$
|
||||
d(\mathbf{x}, \mathbf{y}) = \sqrt{\sum_{i=1}^{n}(x_{i} - y_{i})^{2}}
|
||||
$$
|
||||
|
||||
当 $\small{p \to \infty}$ 时,闵氏距离成为**切比雪夫距离**,即:
|
||||
当 $\small{p \to \infty}$ 时,闵氏距离即**切比雪夫距离**:
|
||||
|
||||
$$
|
||||
d(\mathbf{x}, \mathbf{y}) = \underset{i}{max}(\lvert x_{i} - y_{i} \rvert)
|
||||
$$
|
||||
|
||||
其他的距离度量方式我们等用到的时候再为大家介绍。在使用k 最近邻算法做分类时,我们的数据集通常都是数值型数据,此时直接使用欧几里得距离是一个不错的选择。
|
||||
其他的距离度量方式我们等用到的时候再为大家介绍。在使用 k 最近邻算法做分类时,我们的数据集通常都是数值型数据,此时直接使用欧几里得距离是一个不错的选择。
|
||||
|
||||
<img src="res/02_distance_measurement.jpeg" style="zoom:38%;">
|
||||
|
||||
### 数据集介绍
|
||||
|
||||
接下来为大家隆重介绍一下我们后续会使用到的一个重要的数据集——鸢尾花数据集(iris dataset)。鸢尾花数据集是机器学习领域中最著名、最经典的数据集之一,由英国统计学家 *Ronald A. Fisher*于1936年在他的论文*《The Use of Multiple Measurements in Taxonomic Problems》*中首次引入,被广泛用于机器学习算法的入门和实验。
|
||||
接下来为大家隆重介绍一下我们后续会使用到的一个重要的数据集——鸢尾花数据集(iris dataset)。鸢尾花数据集是机器学习领域中最著名、最经典的数据集之一,由英国统计学家 *Ronald A. Fisher* 于 1936 年在他的论文*《The Use of Multiple Measurements in Taxonomic Problems》*中首次引入,被广泛用于机器学习算法的入门和实验。
|
||||
|
||||
<img src="res/02_iris_dataset.png" style="zoom:38%;">
|
||||
|
||||
鸢尾花数据集共有150条样本,其中包含3种类型的鸢尾花,分别是山鸢尾(Iris setosa)、多彩鸢尾(Iris versicolor)和为吉尼亚鸢尾(Iris virginica),如上图所示,每种各有50条样本。样本数据包含了4个特征(features)和1个类别标签(class label),4个特征分别是花萼长度(Sepal length)、花萼宽度(Sepal width)、花瓣长度(Petal length)、花瓣宽度(Petal width),都是以厘米为单位的正数,数据集中的类别标签有0、1、2三个值,对应上面提到的三种鸢尾花类型。
|
||||
鸢尾花数据集共有 150 条样本,其中包含 3 种类型的鸢尾花,分别是山鸢尾(Iris setosa)、多彩鸢尾(Iris versicolor)和为吉尼亚鸢尾(Iris virginica),如上图所示,每种各有50条样本。样本数据包含了 4 个特征(features)和 1 个类别标签(class label),4 个特征分别是花萼长度(Sepal length)、花萼宽度(Sepal width)、花瓣长度(Petal length)、花瓣宽度(Petal width),都是以厘米为单位的正数,数据集中的类别标签有 0、1、2 三个值,对应上面提到的三种鸢尾花类型。
|
||||
|
||||
#### 数据集的加载
|
||||
|
||||
我们可以通过著名的 Python 机器学习库 scikit-learn 来加载这个数据集,scikit-learn 包含了各种分类、回归、聚类算法,同时还提供了多层感知机、支持向量机、随机森林等模型,覆盖了从数据预处理、特征工程到模型训练、模型评估和参数调优等各项功能,如下图所示。我们推荐大家使用这个库来完成机器学习中的各种操作,scikit-learn 的[官方网站](https://scikit-learn.org/stable/)上面还提供了用户指南、API文档和案例等内容,有兴趣的读者可以自行访问。
|
||||
我们可以通过著名的 Python 机器学习库 scikit-learn 来加载这个数据集,scikit-learn 包含了各种分类、回归、聚类算法,同时还提供了多层感知机、支持向量机、随机森林等模型,覆盖了从数据预处理、特征工程到模型训练、模型评估和参数调优等各项功能,如下图所示。我们推荐大家使用这个库来完成机器学习中的各种操作,scikit-learn 的[官方网站](https://scikit-learn.org/stable/)上面还提供了用户指南、API 文档和案例等内容,有兴趣的读者可以自行访问。
|
||||
|
||||
<img src="res/02_scikit-learn_introduction.png">
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ y = iris.target
|
|||
|
||||
#### 数据集的划分
|
||||
|
||||
通常,我们需要将原始数据划分成训练集和测试集,其中训练集是为了训练模型选择的数据,而测试集则是为了测试模型训练效果保留的数据。对于上面的鸢尾花数据集,我们可以选择80%的数据(120条)作为训练集,保留20%的数据(30条)作为测试集,下面的代码用 NumPy 实现了对数据集的划分。
|
||||
通常,我们需要将原始数据划分成训练集和测试集,其中训练集是为了训练模型选择的数据,而测试集则是为了测试模型训练效果保留的数据。对于上面的鸢尾花数据集,我们可以选择 80% 的数据(120 条)作为训练集,保留 20% 的数据(30 条)作为测试集,下面的代码用 NumPy 实现了对数据集的划分。
|
||||
|
||||
```python
|
||||
# 将特征和标签堆叠到同一个数组中
|
||||
|
|
@ -110,7 +110,7 @@ X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random
|
|||
|
||||
### kNN分类的实现
|
||||
|
||||
下面我们先不用 scikit-learn 而是用基础的数据科学库 NumPy 和 SciPy 来实现 kNN 算法,这样做的目的是帮助大家更好的理解算法原理,在此基础上我们再感受 scikit-learn 的强大并明白其中类、函数、参数等为什么要如此设定,相信大家坚持看下去一定能体会到我的良苦用心。
|
||||
下面我们先不用 scikit-learn 而是用基础的数据科学库 NumPy 和 SciPy 来实现 kNN 算法,这样做的目的是帮助大家更好的理解算法原理,在此基础上我们再感受 scikit-learn 的强大并明白其中类、函数、参数等为什么要如此设定。
|
||||
|
||||
#### 基于NumPy的实现
|
||||
|
||||
|
|
@ -154,7 +154,8 @@ def make_label(X_train, y_train, X_one, k):
|
|||
|
||||
```python
|
||||
def predict_by_knn(X_train, y_train, X_new, k=5):
|
||||
"""KNN算法
|
||||
"""
|
||||
KNN算法
|
||||
:param X_train: 训练集中的特征
|
||||
:param y_train: 训练集中的标签
|
||||
:param X_new: 待预测的样本构成的数组
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ $$
|
|||
这个假设大大简化了计算复杂性,使得我们可以只计算每个特征在给定类别下的概率,而不需要考虑特征之间的相互作用,对应到上面购买飞机延误险的例子,我们可以用下面的方式来计算似然性:
|
||||
|
||||
$$
|
||||
P(起飞机场=双流,到达机场=首都,起飞天气=小雨,降落天气=晴天,执飞航司=川航 \vert 延误) = \\
|
||||
P(起飞机场=双流,到达机场=首都,起飞天气=小雨,降落天气=晴天,执飞航司=川航 \vert 延误) = \\\\
|
||||
P(起飞机场=双流 \vert 延误) \times P(到达机场=首都 \vert 延误) \times P(起飞天气=小雨 \vert 延误) \times P(降落天气=晴天 \vert 延误) \times P(执飞航司=川航 \vert 延误)
|
||||
$$
|
||||
|
||||
|
|
@ -282,7 +282,7 @@ array([[1. , 0. , 0. ],
|
|||
2. **运算开销较小**。预测需要用到的概率在训练阶段都已经准好了,当新数据来了之后,只需要获取对应的概率值并进行简单的运算就能获得预测的结果。
|
||||
3. **受噪声和无关属性影响小**。
|
||||
|
||||
当然,由于做了“特征相互独立”这个假设,朴素贝叶斯算法的缺点也相当明显,因为在实际应用中,特征之间很难做到完全独立,尤其是维度很高的数据,如果特征之间的相关性较大,那么分类的效果就会变得很差。为了解决这个问题,在朴素贝叶斯算法的基础上又衍生出了一些新的方法,包括:半朴素贝叶斯(One Dependent Estimator)、AODE(Averaged One Dependent Estimator)、K依赖朴素贝叶斯、朴素贝叶斯网络、高斯混合朴素贝叶斯等,有兴趣的读者可以自行了解。
|
||||
当然,由于做了“特征相互独立”这个假设,朴素贝叶斯算法的缺点也相当明显,因为在实际应用中,特征之间很难做到完全独立,尤其是维度很高的数据,如果特征之间的相关性较大,那么分类的效果就会变得很差。为了解决这个问题,在朴素贝叶斯算法的基础上又衍生出了一些新的方法,包括:半朴素贝叶斯(One Dependent Estimator)、AODE(Averaged One Dependent Estimator)、K 依赖朴素贝叶斯、朴素贝叶斯网络、高斯混合朴素贝叶斯等,有兴趣的读者可以自行了解。
|
||||
|
||||
### 总结
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
|
||||
在人类的大脑中,神经元(neuron)是负责信息传递和处理的单元,神经元通过化学信号和电信号进行交流,这是人类记忆、感觉、运动等功能的基础。神经元包含了轴突(axon)和树突(dendrite),树突负责接收信号,轴突负责发送信号,此外细胞体也是神经元的重要部分,起到整合和传递信息的作用。神经元之间的连接通过突触(synapse)传递化学信号或电信号来实现,一个神经元可能会与成千上万个神经元连接,构成错综复杂的神经网络。人在刚出生时,大脑中有约 860 亿神经元,大部分神经元是不会再生的,所以这个数字会随着年龄的增长而略为减少。新生儿的大脑拥有数量极其庞大的突触连接,为未来的学习和适应奠定基础。
|
||||
|
||||
神经网络模型是模拟人脑神经元的计算模型,通过多层神经元连接来完成复杂的非线性映射。神经网络由多个层组成,通常包括输入层、隐藏层和输出层。每层中的神经元与前一层的神经元相连接,通过权重调整和激活函数的作用,逐层传递和处理数据,最终完成复杂数据的特征提取和学习。神经网络被广泛应用于模式识别、图像处理、语音识别等领域,是深度学习(Deep Learning)中的核心技术之一。
|
||||
很多科普文章都宣传神经网络模型是模拟人脑神经元的计算模型,通过多层神经元连接来完成复杂的非线性映射,但是没有证据表明大脑的学习机制与神经网络模型机制相同。虽然神经网络这个术语来自于神经生物学,深度学习中的一些概念也是从人类对大脑的理解中汲取灵感而形成的,但是对新手来说,如果认为神经网络与神经生物学存在某种联系,只会让人变得更加困惑。
|
||||
|
||||
### 基本构成
|
||||
|
||||
神经网络一般由多个层组成,通常包括输入层、隐藏层和输出层。每层中的神经元与前一层的神经元相连接,通过权重调整和激活函数的作用,逐层传递和处理数据,最终完成复杂数据的特征提取和学习。
|
||||
|
||||
1. **输入层**:输入层神经元接收输入数据,每个神经元通常对应一个输入特征。输入层的任务是将输入数据传递给下一层的神经元。
|
||||
2. **隐藏层**:隐藏层是网络的核心部分,负责对数据进行特征提取和处理。隐藏层可以有一层或多层,每层的神经元通过权重和激活函数来进行数据处理。深度神经网络通常会包含多层隐藏层,这样能够提取数据中的高阶特征。
|
||||
3. **输出层**:输出层负责将隐藏层的结果转换为最终输出。输出层的激活函数通常与问题类型有关,例如二分类任务可能用 Sigmoid 函数以获得概率,而回归任务则可能直接输出数值。
|
||||
|
|
@ -278,7 +280,123 @@ with torch.no_grad():
|
|||
|
||||
> **说明**:如果还没有安装 PyTorch 库,可以使用命令`pip install torch`进行安装。
|
||||
|
||||
关于深度学习的内容,还在整理和创作中,有兴趣的读者可以关注我的另一个项目:[“深度学习就是大力出奇迹”](https://github.com/jackfrued/Deep-Learning-Is-Nothing)。
|
||||
我们也可以通过神经网络模型来处理回归任务,这里仍然以之前讲回归模型时使用过的“汽车 MPG 数据集”为例,演示如何通过构造神经网络模型解决回归任务,完整的代码如下所示。
|
||||
|
||||
```python
|
||||
import ssl
|
||||
|
||||
import pandas as pd
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.optim as optim
|
||||
from sklearn.metrics import mean_squared_error, r2_score
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
|
||||
ssl._create_default_https_context = ssl._create_unverified_context
|
||||
|
||||
|
||||
def load_prep_data():
|
||||
"""加载准备数据"""
|
||||
df = pd.read_csv('https://archive.ics.uci.edu/static/public/9/data.csv')
|
||||
# 对特征进行清洗
|
||||
df.drop(columns=['car_name'], inplace=True)
|
||||
df.dropna(inplace=True)
|
||||
df['origin'] = df['origin'].astype('category')
|
||||
df = pd.get_dummies(df, columns=['origin'], drop_first=True).astype('f8')
|
||||
# 对特征进行缩放
|
||||
scaler = StandardScaler()
|
||||
return scaler.fit_transform(df.drop(columns='mpg').values), df['mpg'].values
|
||||
|
||||
|
||||
class MLPRegressor(nn.Module):
|
||||
"""神经网络模型"""
|
||||
|
||||
def __init__(self, n):
|
||||
super(MLPRegressor, self).__init__()
|
||||
self.fc1 = nn.Linear(n, 64)
|
||||
self.fc2 = nn.Linear(64, 64)
|
||||
self.fc3 = nn.Linear(64, 1)
|
||||
|
||||
def forward(self, x):
|
||||
x = torch.relu(self.fc1(x))
|
||||
x = torch.relu(self.fc2(x))
|
||||
x = self.fc3(x)
|
||||
return x
|
||||
|
||||
|
||||
def main():
|
||||
# 加载和准备数据集
|
||||
X, y = load_prep_data()
|
||||
# 划分训练集和测试集
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y, train_size=0.8, random_state=3)
|
||||
# 将数据转为PyTorch的Tensor
|
||||
X_train_tensor, X_test_tensor, y_train_tensor, y_test_tensor = (
|
||||
torch.tensor(X_train, dtype=torch.float32),
|
||||
torch.tensor(X_test, dtype=torch.float32),
|
||||
torch.tensor(y_train, dtype=torch.float32).view(-1, 1),
|
||||
torch.tensor(y_test, dtype=torch.float32).view(-1, 1)
|
||||
)
|
||||
|
||||
# 实例化神经网络模型
|
||||
model = MLPRegressor(X_train.shape[1])
|
||||
# 指定损失函数(均方误差)
|
||||
criterion = nn.MSELoss()
|
||||
# 指定优化器(Adam优化器)
|
||||
optimizer = optim.Adam(model.parameters(), lr=0.001)
|
||||
|
||||
# 模型训练
|
||||
epochs = 256
|
||||
for epoch in range(epochs):
|
||||
# 前向传播
|
||||
y_pred_tensor = model(X_train_tensor)
|
||||
loss = criterion(y_pred_tensor, y_train_tensor)
|
||||
# 反向传播
|
||||
optimizer.zero_grad()
|
||||
loss.backward()
|
||||
optimizer.step()
|
||||
|
||||
if (epoch + 1) % 16 == 0:
|
||||
print(f'Epoch [{epoch + 1} / {epochs}], Loss: {loss.item():.4f}')
|
||||
|
||||
# 模型评估
|
||||
model.eval()
|
||||
with torch.no_grad():
|
||||
y_pred = model(X_test_tensor)
|
||||
test_loss = mean_squared_error(y_test, y_pred.numpy())
|
||||
r2 = r2_score(y_test, y_pred.numpy())
|
||||
print(f'Test MSE: {test_loss:.4f}')
|
||||
print(f'Test R2: {r2:.4f}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
```
|
||||
|
||||
输出:
|
||||
|
||||
```
|
||||
Epoch [16 / 256], Loss: 588.2971
|
||||
Epoch [32 / 256], Loss: 530.0340
|
||||
Epoch [48 / 256], Loss: 429.9081
|
||||
Epoch [64 / 256], Loss: 286.5121
|
||||
Epoch [80 / 256], Loss: 133.6717
|
||||
Epoch [96 / 256], Loss: 44.3843
|
||||
Epoch [112 / 256], Loss: 30.3168
|
||||
Epoch [128 / 256], Loss: 24.0182
|
||||
Epoch [144 / 256], Loss: 19.5326
|
||||
Epoch [160 / 256], Loss: 16.4941
|
||||
Epoch [176 / 256], Loss: 14.2642
|
||||
Epoch [192 / 256], Loss: 12.5515
|
||||
Epoch [208 / 256], Loss: 11.2248
|
||||
Epoch [224 / 256], Loss: 10.1825
|
||||
Epoch [240 / 256], Loss: 9.3600
|
||||
Epoch [256 / 256], Loss: 8.7116
|
||||
Test MSE: 8.7226
|
||||
Test R2: 0.8569
|
||||
```
|
||||
|
||||
通过上面的输出可以看到,随着神经网络模型不断的前向传播和反向传播,损失变得越来越小,模型的拟合变得越来越好。在预测的时候,我们利用训练得到的模型参数进行一次正向传播,就完成了从特征到目标值的映射,模型评估的两个指标看起来还不错。目前,神经网络被广泛应用于模式识别、图像处理、语音识别等领域,是深度学习中最核心的技术。对深度学习有兴趣的读者,可以关注我的另一个项目[“深度学习就是大力出奇迹”](https://github.com/jackfrued/Deep-Learning-Is-Nothing),目前该项目仍然在创造更新中。
|
||||
|
||||
### 模型优缺点
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue