机器学习预备知识

学习的是李沐的《动手学深度学习》[2]

深度学习框架

先主要了解三个深度学习框架,MXNET、PYTORCH、TENSORFLOW。

MXNET

MXNet 是开源深度学习框架,允许用户在多种设备(无论是云基础设施还是移动设备)上定义、训练和部署深度神经网络。该框架具备高度可扩展性,可以进行快速的模型训练,并支持灵活的编程模型和多种语言。[1]。它于2015年由亚马逊团队开发。这里就介绍命令行安装方法

1
2
3
pip install mxnet   
#GPU版本的MXNet:
pip install mxnet-cu111

导包不出错则证明安装成功。

1
2
3
4
5
#导入np和npx模块,np模块包含了numpy支持的函数,而npx模块则包含了一些扩展函数
from mxnet import np,npx
#在使用张量之前基本上都会调用下面这个函数,目的是为了兼容mxnet的其他张量处理
npx.set_np()

PYTORCH

PyTorch是一个由Facebook的人工智能研究团队开发的开源深度学习框架 PyTorch最突出的优点之一就是它使用了动态计算图(Dynamic Computation Graphs,DCGs),提供了大量的预训练模型。

1
pip install torch   

安装完成后

1
2
#直接导入
import torch

TENSORFLOW

TensorFlow是由Google Brain团队开发的开源机器学习框架,致力于数据流图的自动微分和深度神经网络计算。它跨平台且灵活,广泛用于构建、训练和部署机器学习模型.

1
pip install tensorflow   

安装完成后

1
2
#直接导入
import tensorflow as tf

基本使用

什么是张量

张量就是一些数值组成的数组,比如说0维张量就是指一个数,数组中只保存了一个数字,又称为标量,可以用ndim属性来查看一个数组的轴的个数,对于轴数的一个简单判断方法就是看第一个数字前面有几个[]括号,所以在标量中只有一个数因此标量中的ndim==0,1维张量就是我们所熟知的向量,2维张量俗称矩阵。

1
2
3
4
5
6
7
#张量的构造方法,以下构造了一个0-11的十二位一维张量。
#MXNET
x = np.arange(12)
#pytoch
x = torch.arange(12)
#tensorflow
x = tf.range(12)

张量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#张量的形状(shape)是一个整数元组,表示张量的轴数以及每个轴含的元素个数

#如(3,5)表示一个2(Dimension)维张量,型如下:
y = np.array([[1,2,3,4,5],
[6,7,8,9,10],
[11,12,13,14,15]
])
#pytorch: torch.tensor([])
#tf: tf.constant([])
#如(3,3,5)型如下:
z = np.array([[[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]
],[[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]],
[[1,2,3,4,5],[6,7,8,9,10],[11,12,13,14,15]]])
#通过shape属性查看张量的形状
print(y.shape)
#reshape函数可以更改张量的形状同时不改变张量的内容
X = x.reshape(3,4)
#使用时还可以用-1来自动算出维度,但注意只能指定一位未知维度
Y = y.reshape(-1,3,5)
#tf中X = tf.reshape(X,(-1,3,5))
#使用ones,zeros函数可以将张量的元素初始化为全1全0,传入的是shape元组
np.ones((2,3,4))
np.zeros((2,3,4))
#从概率分布中获取随机初始化的值,例子如下(这是一个shape为(3,4)的张量,其中元素都是从高斯分布中采样)
#0是均值,1是标准差
np.random.normal(0,1,size=(3,4))
#pytorch: torch.randn(3,4)
#tf: tf.random.normal(shape=[3,4])
#张量的大小是指张量中所含的元素个数
print(y.size)
# pytorch 中用numel()查看size,tensorflow中则用tf.size(X)查看

#张量中所包含的数据类型通常叫dtype,张量的类型可以是 float32、uint8、float64 等\
print(y.dtype)

运算符

按元素运算时,需要两个张量同形,运算就是同一位置的进行运算,x+y,x-y,x/y,x*y,x**y,按元素运算还可使用一些一元运算符, 如求e的幂,可采用np.exp(x),(x为之前定义的张量),除按元素运算外还可以执行线性代数运算。也可以把多个张量连结起来,只需指定连结的轴.

1
2
3
4
5
6
7
8
9
X = x.reshape(3,4)
Y = np.array([[1,2,3,4],
[6,7,8,9],
[11,12,13,14]
])
#axis=0 按行连结;axis=1 按形状的第二个元素连结
np.concatenate([X,Y],axis = 0)
# pytorch: X = torcch.arange(12,dtype=torch.float32).reshape((3,4)) torch,cat((X,Y),dim=0)
#tf: X = tf.reshape(tf.range(12,dtype=tf.float32),(3,4)) tf.concat([X,Y],axis = 0)

可以通过X==Y构造二元张量,及只有true或者false,但需要xy同形. sum()函数对张量中所有元素求和。

1
2
3
4
5
print(X==Y)
print(X<Y)
print(X>Y)
print(X.sum())
#tf: tf.reduce_sum(X)
在计算不同形状的张量时,可通过调用广播机制进行按元素运算, 广播机制通过将张复制扩展使得不同形状的张量扩展为同一形状的张量。 例如下:
1
2
3
4
5
#创建一个3×1和1×2的矩阵相加
a = np.arange(3).reshape(3,1)
b = np.arange(2).reshape(1,2)
print(a+b)
#可以发现a复制了列,b复制了行再相加的
张量也可用索引切片访问,同python数组一样,可用-1访问最后一位元素。[1:3]访问第二和第三位元素,还可通过索引写入元素
1
2
X[0:2,:] = 12
#上是取1和2行并将行中全部写入12
在运行一些操作时比如Y=X+Y时不会在原地运行,而是会新开辟内存来保存X+Y的值,这样的话会导致一个是数据大的时候会额外占用大量内存,二是过去的旧引用会找不到新的内容,因此为了避免以上,可用切片表示法将结果分配给之前分配的数组实现原地执行
1
2
3
4
5
6
7
#新建一个和Y同形的全0块,再把X+Y的值赋给Z,能看到实现了原地执行
Z = np.zeros_like(Y)
#id()查看地址
print(id(Z))
Z[:] = X + Y
print(id(Z))

将深度学习框架定义的张量转换为numpy张量不共享内存,可用item函数或者python内置函数进行转换
1
2
3
4
a = np.array([3.5])
a.item()
float(a)
int(a)

数据预处理

使用pandas软件包预处理原始数据,并转化为张量

读取数据集

创建一个我们将要处理的csv文件 os库中相关函数内容查阅[3]

1
2
3
4
5
6
7
8
9
10
11
12
13
#导入python标准库的os模块,os模块提供了对文件操作路径访问等操作的支持
import os
#创建一个目录,makedirs和mkdir的区别在于makedirs会自动创建父目录而mkdirs不存在父目会报错
os.makedirs(os.path.join('.','data'),exist_ok=True)
data_file = os.path.join('.','data','house_tiny.csv')
print(data_file)
with open(data_file,'w') as f:
f.write('NumRooms,Alley,Price\n') # 列名
f.write('NA,Pave,127500\n') # 每行表示一个数据样本
f.write('2,NA,106000\n')
f.write('4,NA,178100\n')
f.write('NA,NA,140000\n')

导入pandas包并调用read_csv函数查看数据内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
data_file = './data/house_tiny.csv'
data = pd.read_csv(data_file)
print(data)

```

## 处理缺失值
常采用插值法和删除法,插值法用一个替代值补缺失值,而删除法则是直接忽略缺失值。此处主要用插值法。
这里会用到pandas中的iloc函数简单介绍一下。
iloc使用行列的索引位置来寻找值

```python
#读取第二行的值
data1 = data.iloc[1]
#读取第二列的值
data2 = data.iloc[:,1]
#进行切片操作
data3 = data.iloc[1:3,1:3]

与iloc相似的是loc,区别是loc用名称或者标签进行索引。 通过iloc把数据分为inputs和outputs,inputs为数据前两列,outputs为最后一列

1
2
inputs = data.iloc[:,0:2]
outputs = data.iloc[:,-1]

对于inputs中缺少的数值,用同一列的均值替换'NaN'项

1
2
inputs = inputs.fillna(inputs.mean())
print(inputs)

numpy中get_dummies会实现独热编码,独热编码又称为一位有效编码,主要是采用N位状态寄存器来对N个状态进行编码,每个状态都由他独立的寄存器位,并且在任意时候只有一位有效。适用于分类特征,将其特征数值化,例如此处的巷子类型,只有pave和nan,那么就会有两列一列是alley_pave一列是alley_nan,类型是pave的这一行就会显示为1 0 ,而没有的则会显示0 1。

1
2
inputs = pd.get_dummies(inputs,dummy_na = True)
print(inputs)

转换为张量格式

1
2
3
4
5

from mxnet import np
X = np.array(inputs.to_numpy(dtype=float))
y = np.array(outputs.to_numpy(dtype = float))

线性代数

主要了解一个是点乘,降维,向量积,矩阵乘法以及范数。

点乘、向量积、矩阵乘法

点乘主要是用计算向量乘积, 元素乘法再求和也可求出对应的值.\[a,b\in R^d\] 矩阵乘法、向量积也是同样方法实现 \[a^Tb=\sum_{i=1}^N a_ib_i\]

1
2

np.dot(x,y)

降维

求元素和可以达到降维的目的,使张量变为一个标量,还可以指定张量沿哪一个轴来通过求和降低维度,通过sum函数实现:sum(axis=0)指在0轴进行降维,指定轴数进行降维。

1
2
3
4
5
6
a = np.arange(12).reshape(3,4)
a_sum_axis0 =a.sum(axis=0)
print(a)
print(a.shape)


如果我们想沿某个轴计算A元素的累积总和, 比如axis=0(按行计算),可以调用cumsum函数。 此函数不会沿任何轴降低输入张量的维度。

范数

向量的范数是表示一个向量有多大,即以特定的映射方式映射最后计算出的值进行比较,范数听起来很像距离的度量。范数简单来理解就是用于比较的,比如说一个坐标为(2,3),另外一个坐标为(3,2)在这种情况下我们无法比较大小,那么就只有通过降维来达到我们的目的,将二者都降为一维。

\(L_1\)范数

\(L_1\)范数是最常见的范数,其定义如下\[\left\vert\left\vert x \right\vert\right\vert_1 = \sum_{i=1}^n\left\vert x_{i} \right\vert\] 即向量中所有元素绝对值之和,

\(L_2\)范数

\(L_2\)范数定义如下:\[\left\vert\left\vert x \right\vert\right\vert_2 = \sum_{i=1}^n\sqrt{\left\vert x_{i} \right\vert^2}\]

\(L_p\)范数

\(L_n\)范数定义如下:\[\left\vert\left\vert x \right\vert\right\vert_p = \sum_{i=1}^n\sqrt[p]{\left\vert x_{i} \right\vert^p}\]

无穷范数

所有元素中绝对值最大的 \[\left\vert\left\vert x \right\vert\right\vert_\infty = \max(\left\vert x_1 \right\vert,\left\vert x_2 \right\vert...\left\vert x_n \right\vert)\] ## 参考

机器学习预备知识
https://tictanko.github.io/2024/07/28/预备知识/
作者
Jane Z
发布于
2024年7月28日
许可协议