My Little World

learn and share


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于
My Little World

神经网络的相关推导公式

发表于 2024-12-01

矩阵维度

为方便重复计算,减少for循环的使用,在神经网络的计算过程中,尽可能的将数据转成向量进行计算
利用向量的广播能力进行快速计算,神经网络多层传递过程中,矩阵的维度一般遵循以下关系

如果前一层(输入)维度为(m,1),中间层维度是(n, 1), 后一层(输出)维度是(p, 1)
那么 中间层w的维度就是(n, m), b 的维度就是(n,1), b 的维度始终和中间层一致
输出层W的维度(p,n),b 的维度就是(p,1)

参数的矩阵维度关系

向前传播计算过程

一个神经元的计算

每个神经元的计算包括两部分,先计算z,在用激活函数计算a,
同一层不同神经元计算的区别就在于使用不同的参数

如果将参数w和b整理成向量,对当前样本数据进行一次性向量计算
就可以直接得到当前层的直接产出向量

一层神经元的计算

同样,每一层都可以用相同的计算式表示

一组样本数据的计算

通过for 循环进行每一层的计算可得到所有样本数据的预测数据y^

但是通过将输入层维度(m,1) 的向量增加为(m,x)的向量,可以实现一次计算x个样本的效果,从而去掉for循环
如果中间层有n个神经元,输出得到的结果就是(n,x)的矩阵
第n - 1行 上的x个数,每个数代表每个样本数据在中间层第n-1个神经元的计算后的值
第x - 1列 上的n个数,每个数代表第x-i个样本数据在中间层计算后的每个神经元的值

最终经过两层神经元处理后变成,结果变成(1,x)的向量,每个值代表每个样本经过神经网络计算后的预测值

输入输出值矩阵维度之间的关系

小结

其他激活函数

除了sigmoid 激活函数外,常见的激活函数还有Tanh, ReLu,和leaky ReLu,
后三者更常见,且使用更广泛,sigmoid基本只用于二分类场景

为什么不使用线性函数作为激活函数

因为如果使用线性函数作为激活函数,无论神经网络有多少层,都相当于只进行了一次线性函数计算,隐藏层作用消失

不同激活函数的导数



向后传播过程

回顾一下梯度下降的计算过程

对于单个神经元的向后传播过程,就是计算单个神经元参数偏导数的过程

对于多层的神经网络进行带入

小结

同向前传播一样,通过引入向量矩阵,减少for循环

为啥不能初始化参数为0?

如果初始化参数为0或相同值,那么所有节点计算的值都相同,会产生对称性,对后续计算的影响也相同,同样会导致隐藏层节点结算无效
解决办法就是随机初始化参数

一般一开始会将参数随机成比较小的值,如果一开始是比较大的值,z 的值就会比较大,
当激活函数是sigmoid 或者tanh 这样的激活函数时,
计算结果所在的位置就会在梯度比较平缓的地方导致,激活函数处于比较饱和的状态,梯度下降比较慢,影响学习速度

深度网络

向前传播

向后传播

一些超参数

小结

为什么要使用深层网络

使用小的(单层神经元数据量少的)的但是有多层的深层网络,往往会比使用浅层(layer数少)网络计算步骤更简洁
比如下面的电路与或非门计算过程
如果像左侧使用深层网络,每一次层神经元都少一半
如果使用右侧单层神经网络,这一层上的神经元会以2的指数方式计算
总体算下来,深层网络需要处理的神经元会少很多

实验练习

逻辑回归全过程

gitbub[ipynb]链接
实验

思路梳理

数据处理

向量化

实验中要实现对一张图片是否是猫的判断,
首先要对图片进行处理,将图片转换成向量,
一个像素点由RGB三个数据组成, 现在如果横竖都取图片的64个像素点
一张64X64的图片就有64X64=4096个 [r,g,b] 这样的数据,
一张图片的数据表示就是

1
2
3
4
5
6
7
[
[[196 192 190], [193 186 182],...中间还有61组, [188 179 174]], 每一行 有64个
[[196 192 190], [193 186 182],..., [188 179 174]],
... 中间有60行
[[196 192 190], [193 186 182],..., [188 179 174]]
[[196 192 190], [193 186 182],..., [88 79 74]]
] 一共64行

现在把所有数据摊平再转置,就可转成一个[64X64X3=12288, 1]的向量,
也就是m个测试数据组成的矩阵中的一列

1
[[196,], [192,],..., [88,], [79,],[74,]]

A trick when you want to flatten a matrix X of shape (a,b,c,d) to a matrix X_flatten of shape (b ∗ c ∗ d, a) is to use:

1
X_flatten = X.reshape(X.shape[0], -1).T

现在我们有209个训练数据的训练集train_set_x_orig的维度是(209, 64, 64, 3)
a 就是209
现将要将训练集数据一次性转成209列的向量

1
2
m_train = train_set_x_orig.shape[0] // 209
train_set_x_flatten = train_set_x_orig.reshape(m_train, -1).T

train_set_x_flatten 现在的维度就是(12288, 209)
每一列是一张图片的像素数据

数据中心标准化

基于现在处理的是图片的像素数据,所以所有的数据肯定都在0~255之间

One common preprocessing step in machine learning is to center and standardize your dataset,
meaning that you substract the mean of the whole numpy array from each example,
and then divide each example by the standard deviation of the whole numpy array.
But for picture datasets,
it is simpler and more convenient and works almost as well to just divide every row of the dataset by 255 (the maximum value of a pixel channel).

一个常见的预处理步骤是尽可能将数据聚拢到坐标系0附近,常用的方法是对数据进行标准化,
也就是将数据减去均值,然后将数据除以标准差
但是对于图片数据集来说,
除以255(像素通道的最大值),会更简单,而且效果也差不多

1
train_set_x = train_set_x_flatten / 255.

小结

What you need to remember:
Common steps for pre-processing a new dataset are:
Figure out the dimensions and shapes of the problem (m_train, m_test, num_px, …)
Reshape the datasets such that each example is now a vector of size (num_px num_px 3, 1)
“Standardize” the data

常见的数据预处理步骤:

  1. 确定问题的维度和形状(m_train, m_test, num_px, …)
  2. 将数据集重新组织成每个示例都是大小为(num_px num_px 3, 1)的向量
  3. 标准化数据

构建模型

The main steps for building a Neural Network are:

Define the model structure (such as number of input features)
Initialize the model’s parameters
Loop:
Calculate current loss (forward propagation)
Calculate current gradient (backward propagation)
Update parameters (gradient descent)
You often build 1-3 separately and integrate them into one function we call model().

构建一个神经网络模型的主要步骤:

  1. 定义模型结构(例如输入特征的数量,这里是一张图片的12288个rgb数据)
  2. 初始化模型的参数
  3. 循环:
    计算当前损失(前向传播)
    计算当前梯度(反向传播)
    更新参数(梯度下降)
    通常会将1-3分别构建, 然后将它们集成到一个函数中,我们称之为model()。

𝑠𝑖𝑔𝑚𝑜𝑖𝑑函数实现

𝑠𝑖𝑔𝑚𝑜𝑖𝑑(𝑤𝑇𝑥+𝑏)=1/(1+𝑒−(𝑤𝑇𝑥+𝑏))

1
2
3
4
5
6
7
8
9
10
"""
Compute the sigmoid of z
Arguments:
z -- A scalar or numpy array of any size.
Return:
s -- sigmoid(z)
"""
def sigmoid(z):
s = 1/(1+np.exp(-z))
return s

初始化模型的参数

用0来初始化参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"""
This function creates a vector of zeros of shape (dim, 1) for w and initializes b to 0.
Argument:
dim -- num_px * num_px * 3
Returns:
w -- initialized vector of shape (dim, 1)
b -- initialized scalar (corresponds to the bias)
"""
def initialize_with_zeros(dim):
w = np.zeros((dim, 1))
b = 0
return w, b

## 测试
dim = 2
w, b = initialize_with_zeros(dim)

==>
w = [[0.]
[0.]]
b = 0.0

前向向后传播实现

根据公式进行代码实现

最终得到每轮训练的损失函数和梯度

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
35
36
37
38
39
40
# GRADED FUNCTION: propagate

"""
Implement the cost function and its gradient for the propagation explained above

Arguments:
w -- weights, a numpy array of size (num_px * num_px * 3, 1)
b -- bias, a scalar
X -- data of size (num_px * num_px * 3, number of examples)
Y -- true "label" vector (containing 0 if non-cat, 1 if cat) of size (1, number of examples)

Return:
cost -- negative log-likelihood cost for logistic regression
dw -- gradient of the loss with respect to w, thus same shape as w
db -- gradient of the loss with respect to b, thus same shape as b

"""

def propagate(w, b, X, Y):


m = X.shape[1]

# FORWARD PROPAGATION (FROM X TO COST)
A = sigmoid(w.T @ X + b) # compute activation 得到 (m,1) 的矩阵A,m 是训练集样本数
cost = -np.mean(Y * np.log(A) + (1 - Y) * np.log(1 - A)) # compute cost, 在某些 NumPy 的特定版本或上下文中, np.mean 的输出可能是形状为 (1,) 的数组,而不是一个纯标量

# BACKWARD PROPAGATION (TO FIND GRAD)
dw = X @ (A - Y).T / m
db = np.mean(A - Y)

assert(dw.shape == w.shape)
assert(db.dtype == float)
cost = np.squeeze(cost) # 移除多余的单一维度,确保 cost 是标量
assert(cost.shape == ()) # 这里明确要求 cost 的形状是 (),即零维标量。如果 cost 是 (1,),那么会触发断言错误。

grads = {"dw": dw,
"db": db}

return grads, cost

梯度下降实现

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
"""
This function optimizes w and b by running a gradient descent algorithm

Arguments:
w -- weights, a numpy array of size (num_px * num_px * 3, 1)
b -- bias, a scalar
X -- data of shape (num_px * num_px * 3, number of examples)
Y -- true "label" vector (containing 0 if non-cat, 1 if cat), of shape (1, number of examples)
num_iterations -- number of iterations of the optimization loop
learning_rate -- learning rate of the gradient descent update rule
print_cost -- True to print the loss every 100 steps

Returns:
params -- dictionary containing the weights w and bias b
grads -- dictionary containing the gradients of the weights and bias with respect to the cost function
costs -- list of all the costs computed during the optimization, this will be used to plot the learning curve.

1) Calculate the cost and the gradient for the current parameters. Use propagate().
2) Update the parameters using gradient descent rule for w and b.
"""

def optimize(w, b, X, Y, num_iterations, learning_rate, print_cost = False):
costs = [] // 收集每轮计算的损失函数值

for i in range(num_iterations):

# Cost and gradient calculation (≈ 1-4 lines of code)
# 第一轮用初始化w和b计算的损失函数和梯度
# 后面用更新后的w和b计算的损失函数和梯度
grads, cost = propagate(w, b, X, Y)

# 解构梯度
dw = grads["dw"]
db = grads["db"]

# 梯度下降更新参数
w = w - learning_rate * dw
b = b - learning_rate * db

# Record the costs
# 每100轮记录一次损失函数值
if i % 100 == 0:
costs.append(cost)

# 如果需要每100轮打印下损失函数就再打印下
if print_cost and i % 100 == 0:
print ("Cost after iteration %i: %f" %(i, cost))

# num_iterations轮 训练结束后返回最终更新到的参数,梯度,和损失函数集合(可以用于绘制学习曲线)
params = {"w": w,
"b": b}

grads = {"dw": dw,
"db": db}

return params, grads, costs

预测函数

根据公式实现预测函数

𝑌̂ =𝐴=𝜎(𝑤𝑇𝑋+𝑏)

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
'''
Predict whether the label is 0 or 1 using learned logistic regression parameters (w, b)

Arguments:
w -- weights, a numpy array of size (num_px * num_px * 3, 1)
b -- bias, a scalar
X -- data of size (num_px * num_px * 3, number of examples)

Returns:
Y_prediction -- a numpy array (vector) containing all predictions (0/1) for the examples in X
'''
# X 是摊平后数据 (12288, m), X.shape[0] 是影响因素个数 12288 个RGB值, X.shape[1] 是训练集样本数
def predict(w, b, X):

m = X.shape[1]
Y_prediction = np.zeros((1,m))
w = w.reshape(X.shape[0], 1)

# Compute vector "A" predicting the probabilities of a cat being present in the picture
A = sigmoid(w.T @ X + b)

for i in range(A.shape[1]):
# Convert probabilities A[0,i] to actual predictions p[0,i]
# 大于0.5 预测为1 是猫, 小于0.5 预测为0, 不是猫
Y_prediction[0, i] = A[0, i] > 0.5

assert(Y_prediction.shape == (1, m))

return Y_prediction

组装模型

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

"""
Builds the logistic regression model by calling the function you've implemented previously

Arguments:
X_train -- training set represented by a numpy array of shape (num_px * num_px * 3, m_train)
Y_train -- training labels represented by a numpy array (vector) of shape (1, m_train)
X_test -- test set represented by a numpy array of shape (num_px * num_px * 3, m_test)
Y_test -- test labels represented by a numpy array (vector) of shape (1, m_test)
num_iterations -- hyperparameter representing the number of iterations to optimize the parameters
learning_rate -- hyperparameter representing the learning rate used in the update rule of optimize()
print_cost -- Set to true to print the cost every 100 iterations

Returns:
d -- dictionary containing information about the model.
"""

def model(X_train, Y_train, X_test, Y_test, num_iterations = 2000, learning_rate = 0.5, print_cost = False):

# initialize parameters with zeros (≈ 1 line of code)
# 初始化模型的参数
w, b = initialize_with_zeros(X_train.shape[0])

# Gradient descent (≈ 1 line of code)
# 根据训练数据采用梯度下降方法更新参数
parameters, grads, costs = optimize(w, b, X_train, Y_train, num_iterations, learning_rate, print_cost)

# Retrieve parameters w and b from dictionary "parameters"
w = parameters["w"]
b = parameters["b"]

# Predict test/train set examples (≈ 2 lines of code)
# 用训练好的参数预测测试集和训练集的结果
Y_prediction_test = predict(w, b, X_test)
Y_prediction_train = predict(w, b, X_train)

# Print train/test Errors
# 打印训练集和测试集的准确率
print("train accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_train - Y_train)) * 100))
print("test accuracy: {} %".format(100 - np.mean(np.abs(Y_prediction_test - Y_test)) * 100))

# 返回模型训练的损失函数值(学习曲线),训练测试数据集的预测结果(判断模型是否拟合),模型的参数, 学习率,迭代次数等信息
d = {"costs": costs,
"Y_prediction_test": Y_prediction_test,
"Y_prediction_train" : Y_prediction_train,
"w" : w,
"b" : b,
"learning_rate" : learning_rate,
"num_iterations": num_iterations}

return d

# 调用模型
# 注意入参train_set_x, train_set_y, test_set_x, test_set_y, 是经过预处理的数据集
d = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 2000, learning_rate = 0.005, print_cost = True)

模型分析

  1. 预测结果分析

除了函数本身里面的准确率计算,可以初步判断模型是否过拟合训练数据,还可以单独拿出一个测试数据,和 预测数据进行结果比较,进行验证

1
2
3
index = 14
plt.imshow(test_set_x[:,index].reshape((num_px, num_px, 3)))
print ("y = " + str(test_set_y[0,index]) + ", you predicted that it is a \"" + classes[int(d["Y_prediction_test"][0,index])].decode("utf-8") + "\" picture.")
  1. 学习曲线分析
1
2
3
4
5
6
7
# Plot learning curve (with costs)
costs = np.squeeze(d['costs'])
plt.plot(costs)
plt.ylabel('cost')
plt.xlabel('iterations (per hundreds)')
plt.title("Learning rate =" + str(d["learning_rate"]))
plt.show()
  1. 学习率分析 or 超参数分析

增加训练次数,观察学习曲线变化同理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
learning_rates = [0.01, 0.001, 0.0001]
models = {}
for i in learning_rates:
print ("learning rate is: " + str(i))
models[str(i)] = model(train_set_x, train_set_y, test_set_x, test_set_y, num_iterations = 1500, learning_rate = i, print_cost = False)
print ('\n' + "-------------------------------------------------------" + '\n')

for i in learning_rates:
plt.plot(np.squeeze(models[str(i)]["costs"]), label = str(models[str(i)]["learning_rate"]))

plt.ylabel('cost')
plt.xlabel('iterations (hundreds)')

legend = plt.legend(loc='upper center', shadow=True)
frame = legend.get_frame()
frame.set_facecolor('0.90')
plt.show()

应用训练结果进行预测

1
2
3
4
5
6
7
8
9
10
11
my_image = "my_image2.jpg"   # change this to the name of your image file 

fname = "images/" + my_image
image = np.array(plt.imread(fname))
image = image/255.
my_image = np.array(Image.fromarray(np.uint8(image)).resize((num_px,num_px))).reshape((1, num_px*num_px*3)).T // 摊平数据(12288, 1)
#my_image = scipy.misc.imresize(image, size=(num_px,num_px)).reshape((1, num_px*num_px*3)).T
my_predicted_image = predict(d["w"], d["b"], my_image)

plt.imshow(image)
print("y = " + str(np.squeeze(my_predicted_image)) + ", your algorithm predicts a \"" + classes[int(np.squeeze(my_predicted_image)),].decode("utf-8") + "\" picture.")

二分类问题的实践
scikit框架

使用隐藏层实现对非线性数据的分类

题目
我们现在有一堆数据分布成花朵的形状,非线性,如下,

可以看到上面的数据有的是红色,有的是蓝色,假设红色代表支持特朗普,蓝色代表支持拜登
我们希望用一个神经网络来对这些数据进行分类,
分类结果就是输入数据可以直接得到数据是红色还是蓝色的标签
解决思路就想办法对红色和蓝色的数据集中地区进行分块划分,
如果我们还是用sigmoid 函数,那么就会变成线性的,不会得到正确的区块划分

我们希望用一个非线性函数把数据进行精确度更好的划分

The general methodology to build a Neural Network is to:

  1. Define the neural network structure ( # of input units, # of hidden units, etc).
  2. Initialize the model’s parameters
  3. Loop: - Implement forward propagation - Compute loss - Implement backward propagation to get the gradients - Update parameters (gradient descent)

You often build helper functions to compute steps 1-3 and then merge them into one function we call nn_model().
Once you’ve built nn_model() and learnt the right parameters, you can make predictions on new data.

模型结构

涉及方程

向前传播

反向传播

实现

重点关注模型组装好后,如何使用,如何预测,精确度计算,超参数如何训练,迁移学习怎么做

非线性逻辑回归实现代码

L层神经网络实现

整体架构

  1. 向前传播的时候,前L-1层都是先线性然后用relu 函数激活,最后一层是线性然后用sigmoid 函数激活

    The model’s structure is: LINEAR -> RELU -> LINEAR -> SIGMOID.

  2. 计算损失函数
  3. 反向传播的时候,与向前传播相反,除第一层是线性然后用sigmoid 函数激活,后面l-1层是线性然后用relu 函数激活,前面的每一层都是线性然后用relu 函数激活

    The model’s structure is: SIGMOID -> LINEAR -> RELU -> LINEAR -> RELU -> … -> SIGMOID.
    for every forward function, there is a corresponding backward function. That is why at every step of your forward module you will be storing some values in a cache. The cached values are useful for computing gradients. In the backpropagation module you will then use the cache to calculate the gradients. This assignment will show you exactly how to carry out each of these steps.

    使用链式法则, 对下面的线性函数求导dw, db, dA

    得到反向传播计算公式

注意输出层的sigmoid 函数求导

L层神经网络实现代码

运行异常

  1. 参数初始化问题
语句 初始化方式 优缺点
np.random.randn(layer_dims[l], layer_dims[l - 1]) 标准正态分布初始化 简单,但可能导致梯度爆炸或梯度消失,尤其是在深层网络中。
np.random.randn(layer_dims[l], layer_dims[l-1]) / np.sqrt(layer_dims[l-1]) Xavier初始化的变体,np.sqrt(layer_dims[l-1])是上一层神经元个数 提供更稳定的梯度和激活值,适合对称激活函数(如Sigmoid、Tanh)。减少梯度爆炸或梯度消失问题。

如果使用 ReLU 或 Leaky ReLU 作为激活函数,可以采用 He 初始化:

1
parameters['W' + str(l)] = np.random.randn(layer_dims[l], layer_dims[l-1]) * np.sqrt(2 / layer_dims[l-1])

My Little World

一些基础知识

发表于 2024-11-27

深度学习为什么会崛起

随着 数据量的增多,计算能力的提高以及算法的进步,使得深度学习的训练周期变短,可以快速进行迭代更新优化
从而用于工业生成

下面以二分类问题为例,复习一下相关的数学知识和概念

损失函数和成本函数

重新理解一下
损失函数是一个训练数据的预测结果和实际值的差
成本函数是所有训练数据的损失函数的平均值

常见求导公式

1.C’=0(C为常数);
2.(Xn)’=nX(n-1) (n∈R);
3.(sinX)’=cosX;
4.(cosX)’=-sinX;
5.(aX)’=aXIna (ln为自然对数);
6.(logaX)’=1/(Xlna) (a>0,且a≠1);
7.(tanX)’=1/(cosX)2=(secX)2
8.(cotX)’=-1/(sinX)2=-(cscX)2
9.(secX)’=tanX secX;
10.(cscX)’=-cotX cscX;

计算图

向前传播

计算成本函数

向后传播

通过链式求导得到每一轮计算中参数的导数,从而用于进行梯度下降计算

梯度下降计算过程





Neural network programming guideline
Whenever possible, avoid explicit for-loops.
避免for-loops循环计算带来的算力损耗,使用向量对上面两次循环(训练数迭代和参数迭代)进行优化,最终只剩训练次数一次loop 循环

广播

通过使用向量的广播计算,可以大幅度减少for循环的计算成本
广播常见的计算过程如下


练习

使用广播的运算概念,实现下面的softmax 函数

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
def softmax(x):
"""Calculates the softmax for each row of the input x.

Your code should work for a row vector and also for matrices of shape (m,n).

Argument:
x -- A numpy matrix of shape (m,n)

Returns:
s -- A numpy matrix equal to the softmax of x, of shape (m,n)
"""
# Apply exp() element-wise to x. Use np.exp(...).
x_exp = np.exp(x)

# Create a vector x_sum that sums each row of x_exp. Use np.sum(..., axis = 1, keepdims = True).
x_sum = np.sum(x_exp, axis=1, keepdims=True)

# Compute softmax(x) by dividing x_exp by x_sum. It should automatically use numpy broadcasting.
s = x_exp / x_sum

return s

x = np.array([
[9, 2, 5, 0, 0],
[7, 5, 0, 0 ,0]])
print("softmax(x) = " + str(softmax(x)))
==>
softmax(x) = [[9.80897665e-01 8.94462891e-04 1.79657674e-02 1.21052389e-04
1.21052389e-04]
[8.78679856e-01 1.18916387e-01 8.01252314e-04 8.01252314e-04
8.01252314e-04]]

github 实验练习

numpy 官网

My Little World

数据清洗和转换

发表于 2024-10-15

常见数据错误形式

  1. 超出正常数据范围,值或者太大或者太小
  2. 不符合相关校验规则,比如数值类型只能是整形,货币单位应该是美元,但是出现了英镑
  3. 形式错误,比如日期格式错误,电话号码格式错误,不符合相关语法语义规范

对于这样的数据要进行去除清洗处理

数据转换

针对数值,图片,视频,文字不同输入类型,有不同转换方式





小结

  1. 数值类型转换就采用各种归一化的计算公式进行转换
  2. 图片,可以采用裁剪尺寸,下采样,压缩,白化处理
  3. 视频,可以采用截取关键片段,采样关键针降低数据处理陈本
  4. 文字,可以进行词干提取,词形还原以及token化处理

mL 常见算法类型

监督,自监督,半监督,无监督,强化学习

自监督相关概念

决策树相关注意点



二分类评价指标

复杂度解释or解释





李沐机器学习ppt

My Little World

数据标注

发表于 2024-10-14

根据标注数据的目的(数据优化还是训练模型),数据当前的标注情况以及预算情况
可以根据下面的流程进行数据标注

半监督学习

如果一开始有一部分数据可以进行监督学习训练,然后用未标记的数据进行测试,拿到测试结果,
根据测试结果准确性判断是否将当前未标记数据当做标记数据添加到下一轮的训练中


由于这里的工作是进行数据标注,所以可以使用较深的神经网络或者较贵的模型进行训练
以保证得到更准确的标注结果

众包标注

如果有足够的资金预算,可以将数据交给第三方进行标注,然后将标注结果进行汇总

但要面临如何降低标注门槛,标注质量,价格昂贵,标注人员不稳定等问题

主动学习

只将训练结果最不确定的数据,或者最难标记的数据进行人工标注,然后用多个模型投票保证标记准确度

通常与半监督学习结合使用

质量控制

防止标错或者范围有问题,可以选择将一个数据发给多个标注人员进行标注,然后根据标注结果进行投票
但这样做会导致标注成本增加
降低成本的方法可以是,
一是从结果角度思考,先让模型进行推测,如果人工标注与模型推测结果相差较大,则将数据发给多个标注人员进行标注
否则停止任务发送,减少成本;或者发送的前几个人标记结果都一样,就停止发送更多人进行标记
二是从人的角度思考,先给一些有确定标注的数据给标记人员进行标注,如果标注结果与确定标注相差结果较大,说明标注人员能力有问题,进行人员更换

弱监督学习

使用启发式规则通过数据编程得到一些有噪音的标注
通过半自动化的方式生成准确度弱于人工标记,但足以进行模型训练的标注
通过根据数据特征的一系列判断(启发式规则)进行投票,然后将投票结果进行阈值比较,从而判断属于哪个分类标签

小结

三种常见数据标注方式

  1. 半监督学习
  2. 众包标注
  3. 弱监督学习
    对于没有标记的数据也可以用无监督或者自监督学习进行训练
My Little World

强化学习

发表于 2024-10-07

强化学习的主要思想不是告诉算法每个输入的正确输出是什么
而是指定一个奖励函数,告诉它什么时候做的好,什么时候做的不好
算法的工作是自动找出如何选择好的动作

一些概念

以火星探测器为例,在其决定路线的过程中产生的几个概念

  1. S : 当前状态
  2. a : 动作
  3. S’ : 下一个状态
  4. R : 奖励函数
  5. teminal state : 终止状态

    每种路线回报通过计算路上每一步奖励乘以折现系数加和得到

  6. policy : 策略函数,根据当前的状态选择可以获得最大收益的动作

A policy is a function π(s)= a mapping from states to actions, that tells you what action a to take in a given state s.

The goal of reinforcement learning ===>
Find a policy 5 that tells you what action (a = 5(s)) to take in every state (s) so as to maximize the return.

马尔科夫决策过程

未来只取决于当前的名称,而不是到达当前状态之前可能发生的任何事情

状态动作回报函数 Q

当前状态下执行一次函数能够得到的最大回报值
如果能够找到最大回报值也就能知道接下来应该用什么动作

贝尔曼公式



优化

面对环境随机的情况,动作实际执行过程可能存在多个可能路线,导致每次得到的最大回报值不同,因此计算当前状态最大收益时取所有路线情况的平均值进行计算
即使用期望回报值进行计算

DQN 算法

D: deep learning
Q: Q function
N: Network

对于连续状态值的情况,使用神经网络训练Q函数进行深度强化学习



By using experience replay we avoid problematic correlations, oscillations and instabilities. In addition, experience replay also allows the agent to potentially use the same experience in multiple weight updates, which increases data efficiency.
通过使用经验重放,我们可以避免有问题的相关性、振荡和不稳定性。此外,经验重放还允许代理在多次权重更新中使用相同的经验,从而提高数据效率。

优化

优化神经网络结构

上面将s和a作为X 同时参与训练,最终只会得到一个动作a最大回报函数值,需要进行多次运算
如果仅将s作为输入,输出层产生多个a的回报值,就可以根据回报值大小选择相应的动作


epsilon-greedy policy

选择action 过程中,如果一直按Q值最大原则选择action,万一初始值特别小无法开启我们想要的第一步程序,就会导致无法进行后续的action
epsilon-greedy policy 方案就是找一个合适的阈值epsilon,比如说0.05,
95%的时间选择最大Q值action (贪婪剥削策略)
5%的时间选择随机选择action(探索策略)
这样就可以避免选到固定不符合预期的action,开放一定的窗口有可能选到其他的action
epsilon 大小 类似于梯度,随训练过程进行会逐渐变小,变小的过程,模型也就学会了如何选择更有可能选择符合预期的action

小批量

训练数据如果非常庞大,在训练过程中可能会造成时间消耗,为了提高训练速度,可以采用小批量的方式进行
将训练数据分成多个批次,每次迭代用不同批次数据,虽然梯度会比较嘈杂,但还是会朝着梯度下降的方向进行



软更新

在更新参数过程中,每次按比例更新参数,每次仅更新部分比例的参数,可以使强化学习更好的收敛

强化学习的一些限制

实验练习

My Little World

推荐系统

发表于 2024-10-06

下面以根据电影评分推荐电影为例,介绍推荐系统的开发过程

思路整理

根据电影的特征,用户对每个电影都会有一个评分(0-5分),比如电影A的评分是5分,电影B的评分是4分,电影C的评分是3分
一般情况下,用户对某电影评分越高,说明后续对该类型电影的青睐度越高,对于系统来说越值得推荐给用户
即系统需要预测用户对某个电影X的评分,从而决定是否推荐给用户
系统需要依赖的数据是电影的特征数据(X)和以往用户对电影的评分数据(Y)
根据二者的关系,计算出相关的算法参数
当有需要预测一个电影评分的时候,输入待评分电影特征即可得到评分,然后根据阈值判断是否推荐给用户
下面是对一个观众的电影评分预测过程

对应的成本函数

如果训练集有多个用户的评分数据,拿到所有用户的参数后加合,就可以预测大众用户对某个电影的整体评分情况

协同过滤算法

对于电影的评分,一开始不能确定使用电影的哪些特征,协同过滤算法将输入,电影的特征X, 也看做是一个参数参与成本函数的计算
从而利用梯度下降过程找到合适的参数和特征值

推导过程

  1. 已知多个人对一部电影的评分和相关参数,可以反推出X 的 情况
  2. 如果现在已知多个人对一部电影的评分和相关参数,可以对电影特征X进行成本函数计算
    加和之后可以对多个电影的特征进行预测
  3. 观察成本函数的公式,现在加和参数和特征的成本函数,

  4. 可以发现, 梯度下降过程,可以同时找出多个人对电影评分参数和对多部电影的特征值推测

协同在这里的体现在于多个用户对一部电影进行了评价,通过合作得到了对电影的整体评价,同时可以预测出能够代表这部电影的特征值
反过来,可以预测尚未对同一部电影进行评分的其他用户的评分
即从多个用户收集数据,然后预测其他用户的评分

线性回归转向二进制分类

基于线性回归的推荐系统适合于上面评分有连续值的推测,基于上述思路,将评分结果通过逻辑函数转成二进制结果
即可实现二进制分类问题的预测


优化

均值归一化

对于尚未对电影作为任何评价的用户,如果参数为0,那么预测的评分结果为0,会极大影响推荐的准确性
因此,先对多用户评分计算均值,然后对所有用户的评分减去均值,得到新的评分,在新的评分上进行参数获取
进行评分预测的时候再把均值加回来,这样即使参数为0,预测的评分值也是之前评分的均值,对整体评分meian值不会有影响

如何找到相似的推荐

找到与当前item 距离最近的其他item

协同过滤的限制

  1. 对冷启动问题不友好
  2. 不能直接获取到有价值的特征数据,可能是关于观众或者电影的片面的信息,只能从这些信息上推测用户的爱好

基于内容的推荐算法

对比基于协同过滤的推荐算法(根据用户对相似item的评分进行推荐)
基于内容的推荐算法同时基于用户和item的特征,通过计算item 和用户的匹配度,来判断用户是否对该item感兴趣

主要思路

利用神经网络从用户特征和item 特征中提取n 个特征,计算二者的点积从而判断用户是否对item感兴趣,是否要推荐给用户




从大目录中进行推荐

  1. 进行检索,找出候选列表
    但是检索过程需要注意,通过对更多的项目进行检索可以得到更好的结果但是检索的速度回变慢,
    为了分析优化权衡二者,可以实施离线实验观察新增的检索项是否增加了检索结果的相关性

  2. 对候选列表进行fine-tune排序找出得分最高的item给用户



My Little World

异常检测

发表于 2024-10-05

异常检测

异常检测是机器学习中一个重要的概念,它是指在数据中检测出不符合预期的数据点,以便及时发现和处理异常情况。

检测方法:密度估计

密度估计是异常检测中的一种方法,它通过计算数据的密度分布来识别异常数据点。
通过将特征值的可能性进行乘积计算,得到数据的密度,然后跟阈值进行比较,判断当前数据是否正常。


高斯分布

高斯分布的位置受数据集的平均值𝜇和方差𝜎^2 决定

𝜇 决定钟形最高点在x轴上的位置
𝜎^2 决定钟形的宽度,因为整个钟形面积为1,所以,如果𝜎^2 变小,那个整个钟形会变得很高

异常检测算法步骤

  1. 在训练数据中选择你认为可能会引起异常的数据的n个特征值
  2. 计算各个特征值的平均值𝜇和方差𝜎^2
  3. 计算每个特征值的密度,如果密度小于阈值,则认为是异常数据

开发过程中如何评估异常检测系统

通常采用实数评估方案,就是可以用一个具体的数值小小来衡量算法的好坏
假设训练数据中的数据都是正常的,存在标签0
在交叉验证和测试数据中,存在少量异常数据,标签为1
测试算法好坏的标准就是能否将异常数据识别出来
如果是特别少量的异常数据,可以仅通过交叉验证来评估测试好坏
从而决定合适的阈值大小


另外的评估方法可参考二分类错误度量
相关的衡量指标,真假值,精确率,召回率,F1 score等

如何选择异常检测算法和监督学习

异常检测算法适用于

  1. 正常数据少量但是有大量异常数据
  2. 异常的特征值是未知的,且是多样的

监督学习算法适用于

  1. 存在大量异常和正常数据
  2. 有足够数据告诉算法什么是正常的数据,什么是异常的数据
    将来出现的异常数据很可能是之前训练集中出现过的异常数据

如何选择要使用的特征

  1. 选择符合高斯分布的特征,如果不能拟合高斯分布,可以通过取对数,开方等方式进行特殊处理后进行拟合
    但要注意,训练数据如果有对特征值进行特殊处理,那么交叉验证集合测试集也要进行相同的处理

  2. 对于误判的异常数据,可以通过增加特征值来进行弥补,保证数据在新加的特征值上存在异常大或者异常小的数据

  1. 可以在已有的原始特征值基础上创造新的特征值参与运算
My Little World

Kmeans 聚类算法

发表于 2024-10-03

无监督学习算法一

什么是聚类

将输入数据分成多个类别,每个类别包含一组相似的数据点的过程就是聚类,分好的类被称为cluster

聚类算法k-means处理过程

  1. 随机选择k个点作为初始的中心点, 计算每个点到中心点的距离,将每个点分配到距离最近的中心点所属的类别中
  2. 计算每个类别的中心点(平均值),并更新中心点,重复步骤1
  3. 直到中心点不再变化,或者达到最大迭代次数

具体实现(伪代码)


成本函数


如何初始化中心点

随机选择k个点作为初始的中心点(k小于m),计算最终中心点和损失函数
重复N次,选择损失函数最小的中心点作为最终的中心点

如何选择K的数量

取决后续如何使用分类好的集群数据

压缩图像应用

My Little World

决策树模型

发表于 2024-09-30

决策树模型是通过计算特征纯度后,选取最大纯度值的特征作为决策节点,
将数据根据是否符合当前特征节点一份为二,再根据特征纯度,继续划分,
最后根据停止划分规则进行数据分类或推测的模型

创建过程

决策树创建过程需要考虑两件事

  1. 在每个节点上如果选择根据什么特征进行数据分类
    Maximize purity
    如果一个特征在把数据分成两组之后,使分组后的数据能够最大程度的趋于同一类,那么这个特征就是纯度高的特征,
    即 如果这个特征能够直接决定数据属于哪个分类的程度越高,纯度就越高
    比如用DNA特征判断猫狗分类比用耳朵是尖的还是软的更直接,DNA特征就是最大纯度的特征

  2. 什么时候停止数据分类
    a. 当一个节点里面的数据都属于同一类的时候
    b. 到达树的深度最大值的时候,树越深,过拟合越有可能,计算成本越高
    c. 当特征纯度(熵)低于某个阈值的时候
    d. 当节点里的数据个数低于某个阈值的时候

熵

可以理解为数据的混乱程度,如果数据特别混乱,则值越大,返回数据如果种类单一,则值越小,趋近0
这里用熵来计算特征的非纯度或者较杂质程度,
如果根据某个特征分类后的数据的熵 越小,说数据越干净,杂质越少
反之,如果得到的熵越大,说数据越混乱,不同类的数据越多
如下面判断是否是猫的问题
p1 代表是每组数据中猫的比例,都是猫或狗的话熵 是0,5:5 的时候熵 最大值为1,数据最混乱

具体熵 的计算公式如下

信息增益

在了解熵的含义后,用下面的计算过程选择节点的判断特征
根节点的熵减去分类后两个节点熵的加权平均值,值越大说明分类后数据越纯了

这个计算方式得到的值就叫信息增益
即特征信息增益越大,在分类过程中,能够把数据分的越纯

小结

决策树学习过程

对于每个节点,都要像对待根节点一样
根据拿到的数据先找到最大信息增益的特征然后进行分类
整个过程就是一个递归的过程,直到满足停止分类的规则为止

多特征值处理办法

one-hot

If a categorical feature can take on 𝑘 values, create 𝑘 binary features (0 or 1 valued).
如果一个特征有大于2个以上的N可枚举值,那么将当前特征拆分成N个新的代表相应枚举值的特征即可

连续值

如果一个特质的值是连续值,不可枚举,那么需要设定一个阈值,大于该阈值一类,小于则是另一类,从而实现对该特征的二分类
阈值的选取还是通过计算信息增益,选取能够使信息增益值最大的阈值参与分类
一般情况下先对所有数据按这个特征值排序,然后选取排序列表中两个数据间的中点做阈值进行信息增益计算,
多轮计算后再从中选取信息增益最大的阈值

回归树

上面是使用决策树进行分类计算
接下来使用方差对连续数据进行推测,就是回归树
如下图,根据前三个特征,推测weight 的值,weight 是个连续的值,不能枚举的

决策树练习

多个决策树

单个决策树对训练数据非常敏感,只要更改一个训练数据,就有可能更改信息增益排序,
从而影响节点特征选择,进而导致整棵树发生变化,使得算法失去健壮性
解决办法就是构建多个树,让他们投票最终的预测结果,使整体的算法对任何单个树可能在做什么不那么敏感

放回抽样

一共有m个训练数据,每次从m个数据中随机抽取1个数据,直到抽取到m个数据,抽取到的数据可能是重复的

随机森林算法

使用放回抽样的数据选取方法,每次拿到m个训练数据,用这个m个训练数据训练决策树,重复 B(小于100)次,
得到B棵决策树,从而形成决策树森林对预测结果进行投票,这种算法就是随机森林算法

B 如果大于100 一个是训练效果会下降,推测准确性降低,另外一个就是会增加计算成本,使算法变得复杂,得不偿失

随机特征选取

对于具备N个特征的数据,通常选择N的K个特征子集进行训练,如果N特别大,K一般等于N的平方根

XGBoost 随机森林增强算法

除了第一次等概率的从m个训练数据中抽样new dataSet 外,后续的每一轮抽样,都将前一轮推测失败的训练数据的权重加大,
使被抽取到的概率变高,尽可能的将推测失败的数据参与到后续的训练中,从而推动算法更快的学习,并学习的更好,提高算法的准确性

这种算法又称为XGBoost 算法,是随机森林算法的改进版,优点如下

决策树 VS 神经网络

决策树& 决策森林

适合结构化数据(可以用表格表示的数据)
不适合非结构化数据(音视频,图像)
小的决策树可以被人类解释推测过程
训练速度快,缩短算法迭代循环周期,更快的提高算法性能

神经网络

对于所有数据类型都很友好,包括结构化和非结构化
训练速度比决策树要慢
但可以轻松实现迁移学习,但是决策树每次训练只能特定的特征,得到特定的决策树
方便构建多模型系统,神经网络间串联方便

My Little World

机器学习开发过程

发表于 2024-09-29

整个开发过程是一个选择框架,训练模型,诊断模型循环的过程

错误分析

除了从高偏差高误差角度对模型进行分析外,还可以对mcv 产生错误分类的角度对模型进行分析

可以从交叉验证集测试产生的错误中进行分析
通过将错误进行归类统计,找出对模型影响比例较大的错误和比例较小的错误
从而调整模型训练的方向,已解决上面遇到的问题

如果交叉验证集产生错误的数据比较庞大,可以选择进行随机抽取一定小批量的数据进行错误分类,以节省人力

添加数据

通过引入更多数据完善模型的判断,更关注通过注入的数据引发的对模型的训练结果的影响

数据增强

Augmentation: modifying an existing training example to create a new training example.
在原有数据基础上,通过添加特定种类的噪声,形成新的测试数据,从而完善特定种类的错误判断
对于图片和音频数据都适用

但是对添加随机或者无意义噪声产生的数据进行训练,对于模型训练不会有多大帮助

数据合成

Synthesis: using artificial data inputs to create a new training example.
直接由计算机合成训练过程中使用的数据,通常用于计算机视觉训练的场景

迁移学习

在已有大模型训练结果基础上,通过修改输出层结果使之符合自己使用场景的训练方法
好处是,在数据有限的情况下,可以直接使用输出层之前的参数开始训练,减少自己从头开始训练的工作

例如下面这个使用1000+分类的训练识别数字0-9的模型,只是在输出层将1000+ 输出改成10种输出,在此基础上开始训练

一般训练步骤为下载相同输入(文本的下载文本的,音视频的下载音视频的)的预训练模型,然后用自己的数据进行训练(fine tuning)

完整开发流程

部署阶段

通常应用层跟模型通过Api 进行通信,用户输入x, 模型返回预测值y^
软件工程师需要注意

  1. 尽可能的保障低成本的计算出具有可靠性和有效性的预测结果
  2. 可以进行大规模用户扩展使用
  3. 在用户隐私允许同意的情况下进行日志记录输入和输出
  4. 对模型进行系统监控,比如根据上面日志的记录,计算出因为当前数据变化导致计算结果不准时,判断是否让模型进行进一步优化
  5. 保障模型更新,在上一步进行模型优化后要保证能够将老的模型替换成新模型

避免道德偏见伦理问题

  1. 建议多元化(多背景,多种族)团队,上线前进行头脑风暴,探索可能对弱势群体造成伤害的可能
  2. 参考行业标准
  3. 上线前通过技术诊断产生的伤害可能性,从而决策是否可以上线
  4. 制定延缓计划,上线后观测可能产生的伤害,及时进行回滚处理

二分类错误度量

在对倾斜数据集(y=1 和y = 0 所占比例不是5:5)进行训练时,
判断模型预测结果好坏通常交叉验证集的数据计算精确率和召回率两个指标衡量

如果二者都趋近0或1时,说明当前的模型不是一个有用的模型,一直在打印0或1
只有二者值都很大时,才说明算法是有用的

精确率表示实际上y = 1的可能性
召回率表示模型计算出y = 1 的可能性

对于精确率和召回率的衡量

一种是通过设置阈值大小去权衡二者,从而进行取舍
提高阈值,会增加精度,降低召回率
降低阈值,会降低精度,提高召回率

另外一种是使用F1 score分数(调和平均数),自动计算出最佳的精度和召回率,从而选择对应的算法

123…27
YooHannah

YooHannah

263 日志
1 分类
23 标签
RSS
© 2025 YooHannah
由 Hexo 强力驱动
主题 - NexT.Pisces