本文代码只讨论核心部分, 完整代码上传CSDN资源并在kaggle公开:
https://www.kaggle.com/laugoon/homework2
https://download.csdn.net/download/lagoon_lala/19032029
目录
任务介绍
二元分类, 通过个人资料, 预测其年收入是否超过5万美元.
需要用到的数据集有: train.csv, test_no_label.csv, X_train, Y_train, X_test
其中train.csv, test_no_label.csv为原始数据, X_train, Y_train, X_test为助教处理过.
X_train, X_test : 每行一个样本有510维度, 不必全部使用.
Y_train: label = 0含义为“<= 50K” 、 label = 1则“ >50K ”
提交格式:
测试集27622有个样例
第一行: “id, label”
第二行以后: “id, prediction”
CSV(comma seperated values) format
评分依据为正确率
需要手刻 gradient descent 實作 logistic regression, probabilistic generative model. 也就是不能用套件.
需要达成的分数:
Public simple baseline(1%): 0.88617
Public strong baseline(1%): 0.89052
如果给助教临时跑, 建议固定random seeds, 不然结果可能有差距.
预测思路
"這個資料集是由 UCI Machine Learning Repository 的 Census-Income (KDD) Data Set 經過一些處理而得來。
在訓練過程中,只有 X_train、Y_train 和 X_test 這三個經過處理的檔案會被使用到,train.csv 和 test.csv 這兩個原始資料檔則可以提供你一些額外的資訊。"
对率回归
数据准备
下載資料,並且對每個屬性做正規化,處理過後再將其切分為訓練集與發展集(development set)。
新建notebook按照自动生成的代码可以获得文件的路径:
import os for dirname, _, filenames in os.walk('/kaggle/input'): for filename in filenames: print(os.path.join(dirname, filename)) |
/kaggle/input/ml2020spring-hw2/data/X_train |
写预测结果输出的时候遇到一点报错:
Read-only file system: '/kaggle/input/ml2020spring-hw2/output_logistic.csv' |
查看最开始自动生成代码中的注释
ou can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using "Save & Run All" |
更改目录.
根据获得的文件路径, 读取csv保存在numpy数组
with open(X_train_fpath) as f: next(f) X_train = np.array([line.strip('\n').split(',')[1:] for line in f], dtype = float)#strip()表示删除掉数据中的换行符,split(‘,’)则是数据中遇到‘,’ 就隔开 |
X_train, Y_train: (array([[33., 1., 0., ..., 52., 0., 1.], ..., [48., 0., 0., ..., 0., 0., 1.]]), array([1., 0., 0., ..., 0., 0., 0.])) |
对训练集测试集的X做标准化.
if train: X_mean = np.mean(X[:, specified_column] ,0).reshape(1, -1)#reshape(1,-1)转换为行数1, 列数根据行数计算 X_std = np.std(X[:, specified_column], 0).reshape(1, -1) X[:,specified_column] = (X[:, specified_column] - X_mean) / (X_std + 1e-8)#(x-μ)/σ |
X_train, X_mean, X_std = _normalize(X_train, train = True) X_test, _, _= _normalize(X_test, train = False, specified_column = None, X_mean = X_mean, X_std = X_std)#'_'做变量名合法, 作为无用的临时变量 |
相关知识
shape[0]:表示矩阵的行数; shape[1]:表示矩阵的列数
https://blog.csdn.net/xiasli123/article/details/102932607
reshape:
https://www.jianshu.com/p/d9df005636a6
python下划线作用:
https://blog.csdn.net/tcx1992/article/details/80105645
将数据分割为训练集, 发展集
train_size = int(len(X) * (1 - dev_ratio)) return X[:train_size], Y[:train_size], X[train_size:], Y[train_size:] |
train_size = X_train.shape[0]#训练集行数 print('Size of training set: {}'.format(train_size)) |
Size of training set: 48830 Size of development set: 5426 Size of testing set: 27622 Dimension of data: 510 |
工具函数
训练过程中可能重复使用
洗牌
randomize = np.arange(len(X))#arange(len(X))返回0,1...len(X) np.random.shuffle(randomize)#shuffle()方法将序列的所有元素随机排序 return (X[randomize], Y[randomize]) |
相关知识: arange, shuffle
https://zhuanlan.zhihu.com/p/266619783
计算sigmoid函数作为概率
用的概率分布是高斯分布, 则P可以代入σ, 即sigmoid函数:
$$ P\left( C_{1} \middle| x \right) = \sigma\left( z \right) \\ \sigma\left( z \right)= \frac{1}{1 + exp\left( {- z} \right)} $$
np.clip(1 / (1.0 + np.exp(-z)), 1e-8, 1 - (1e-8))#clip将数限定到范围1e-8和1-(1e-8)中 |
相关知识: clip, sigmoid函数(详细见上篇文章)
https://blog.csdn.net/weixin_44791964/article/details/100000373
对率回归
使用sigmoid函数作为P时, 输入的z为:
$$ z= {w \cdot x + b}=\sum_i w_ix_i+b $$
_sigmoid(np.matmul(X, w) + b)#matmul矩阵相乘 |
相关知识: matmul
https://blog.csdn.net/alwaysyxl/article/details/83050137
通过把对率回归函数的结果四舍五入(round),得到每行X真正的预测值.
np.round(_f(X, w, b)).astype(np.int) |
计算预测精确度
acc = 1 - np.mean(np.abs(Y_pred - Y_label))#误差1/n*Σ|y*-y| |
梯度和损失
參考李宏毅逻辑回归PPT, P12梯度及損失函數計算公式。(在notebook写公式和CSDN一样可用Tex, 很方便)
计算交叉熵作为损失函数
y hat=1, 属于类别1, y hat=0, 属于类别2,
对以下两个分布(假设均为Bernouli两点分布)做交叉熵. Distribution p:
$$ p\left( {x = 1} \right) = {\hat{y}}^{n}\\ p\left( {x = 0} \right) = {1 - \hat{y}}^{n} $$
交叉熵可衡量两个分布接近程度:
$$ H\left( {p,q} \right) = - {\sum_{x}{p\left( x \right)ln\left( {q\left( x \right)} \right)}} $$
代入似然函数可表示为:
$$ - lnL\left( {w,b} \right) = {\sum_{n}{- \left\lbrack {{\hat{y}}^{n}lnf_{w,b}\left( x^{n} \right) + \left( {1 - {\hat{y}}^{n}} \right) ln\left( {1 - f_{w,b}\left( x^{n} \right)} \right)} \right\rbrack}} $$
cross_entropy = -np.dot(Y_label, np.log(y_pred)) - np.dot((1 - Y_label), np.log(1 - y_pred))#log默认以e为底 |
相关知识:log(), 交叉熵(详细查阅上篇文章)
https://blog.csdn.net/weixin_44383134/article/details/87866307
计算梯度
梯度下降的更新公式
$$ w_{i}\leftarrow w_{i} - \eta{\sum_{n}{- \left( {{\hat{y}}^{n} - f_{w,b}\left( x^{n} \right)} \right)x_{i}^{n}}} $$
该公式中间的因子, 为似然函数lnL对wi的偏微分:
$$ \frac{\partial lnL\left( {w,b} \right)}{\partial w_{i}} =-\sum_{n}{ \left( {{\hat{y}}^{n} - f_{w,b}\left( x^{n} \right)} \right)x_{i}^{n}} $$
y_pred = _f(X, w, b)#对率回归 pred_error = Y_label - y_pred#误差 w_grad = -np.sum(pred_error * X.T, 1)#sum参数axis=1是压缩列,即将每一行的元素相加,将矩阵压缩为一列 b_grad = -np.sum(pred_error) |
相关知识: sum(), 损失函数最小化(详见上篇)
https://zhuanlan.zhihu.com/p/85790648
训练
我們使用小批次(batch)梯度下降法來訓練。訓練資料被分為許多小批次,針對每一個小批次,我們分別計算其梯度以及損失,並根據該批次來更新模型的參數。當一次迴圈(循环, 迭代)完成,也就是整個訓練集的所有小批次都被使用過一次以後,我們將所有訓練資料打散並且重新分成新的小批次,進行下一個迴圈,直到事先設定的迴圈數量達成為止。
初始化wb
w = np.zeros((data_dim,)) #zeros第一个参数为形状 b = np.zeros((1,)) |
相关知识: zeros()的第一个参数shape为整数或tuple, 表示矩阵形状
https://blog.csdn.net/weixin_44805104/article/details/102746080
https://blog.csdn.net/u010852680/article/details/77745468
np.zeros((5,))与np.zeros(5)的效果相同, 都是:
array([0., 0., 0., 0., 0.]) |
当shape为二元组时, 则第一个数为行数, 第二个为列数, 如np.zeros((5,2))得到:
array([[0., 0.], [0., 0.], [0., 0.], [0., 0.], [0., 0.]]) |
计算梯度
w_grad, b_grad = _gradient(X, Y, w, b) |
利用梯度下降更新参数w b,学习率随时间(step)减少
w = w - learning_rate/np.sqrt(step) * w_grad |
计算Y预测值:
y_train_pred = _f(X_train, w, b) Y_train_pred = np.round(y_train_pred) |
计算精确度:
train_acc.append(_accuracy(Y_train_pred, Y_train)) |
计算损失值:
train_loss.append(_cross_entropy_loss(y_train_pred, Y_train) / train_size)#/ train_size消除训练集与发展集大小不同带来的影响 print('Training loss: {}'.format(train_loss[-1]))#[-1]表示数组中最后一位 |
Training loss: 0.2713554352464059 Development loss: 0.2896359675026287 Training accuracy: 0.8836166291214418 Development accuracy: 0.8733873940287504 |
作损失, 精度曲线
plt.plot(train_loss)# x可省略,默认[0,1..,N-1]递增 plt.plot(dev_loss) plt.title('Loss') plt.legend(['train', 'dev'])#默认参数: 图例的名称 plt.savefig('/kaggle/working/loss.png') plt.show() |
相关知识: savefig
https://www.cnblogs.com/cgmcoding/p/14244735.html
预测测试集
預測測試集的資料標籤並且存在 *output_logistic.csv* 中。
predictions = _predict(X_test, w, b) with open(output_fpath.format('logistic'), 'w') as f: f.write('id,label\n') for i, label in enumerate(predictions):#enumerate列出数据和生成数据下标 f.write('{},{}\n'.format(i, label)) |
筛选最大(显著)的几个weight, 即得到最有用的特征
ind = np.argsort(np.abs(w))[::-1]#argsort从小到大排序, ::-1从后向前读取 with open(X_test_fpath) as f: content = f.readline().strip('\n').split(',') features = np.array(content) for i in ind[0:10]: print(features[i], w[i]) |
相关知识:
argsort
https://blog.csdn.net/qq_38486203/article/details/80967696
分片
https://blog.csdn.net/ITOMG/article/details/88683256
输出的结果:
Not in universe -4.031960278019251 Spouse of householder -1.625403958705141 Other Rel <18 never married RP of subfamily -1.4195759775765404 Child 18+ ever marr Not in a subfamily -1.2958572076664745 Unemployed full-time 1.1712558285885912 Other Rel <18 ever marr RP of subfamily -1.167791807296237 Italy -1.093458143800618 Vietnam -1.0630365633146415 num persons worked for employer 0.938992277356651 1 0.8226614922117185 |
概率生成模型
Porbabilistic generative model
實作基於 generative model 的二元分類器,理論細節請參考李宏毅分类一节。
准备数据
訓練集與測試集的處理方法跟 logistic regression 一模一樣,然而因為 generative model 有可解析的最佳解,因此不必使用到 development set。(对率回归的梯度下降参数找不准点, 发展集用来模拟泛化后误差)
读取numpy数组的方式与对率回归相同, 不再赘述.
平均值和协方差
在 generative model 中,我們需要分別計算兩個類別內的資料平均與共用的變異(in-class mean and covariance)。
将两个类别的样本分开存放
X_train_0 = np.array([x for x, y in zip(X_train, Y_train) if y == 0]) |
计算类内平均值
协方差公式详细可参见笔记4:分类. 极大似然函数L分别对μ, Σ求偏导,解出微分是0的点,即使L最大的那组参数.
得两者解析解的公式, μ是数学期望:
$$ \mu^{*} = E(X)=\frac{1}{n}{\sum_{n = 1}^{n}x^{n}} $$
mean_0 = np.mean(X_train_0, axis = 0)#axis = 0:压缩行,对各列求均值,返回 1* n 矩阵 |
计算类内协方差
$$ \Sigma^{*} = cov(X,X)=E[(X-\mu)(X-\mu)^T]=\frac{1}{n}{\sum_{n = 1}^{n}\left( {x^{n} - \mu^{*}} \right)}\left( {x^{n} - \mu^{*}} \right)^{T} $$
for x in X_train_0: cov_0 += np.dot(np.transpose([x - mean_0]), [x - mean_0]) / X_train_0.shape[0] |
对类内协方差加权平均, 获得共用协方差.
cov = (cov_0 * X_train_0.shape[0] + cov_1 * X_train_1.shape[0]) / (X_train_0.shape[0] + X_train_1.shape[0]) |
计算weights, bias
權重矩陣與偏差向量可以直接被計算出來,算法可以參考李宏毅分类一节
其中需要计算协方差矩阵的逆. 由于协方差矩阵可能是奇异的, np.linalg.inv() 可能出现较大数值误差. 通过 SVD 分解, 可用有效精确地得到矩阵的逆. 这一部分可参考西瓜书附录的奇异值分解, 分解公式:
$$ \mathbf{S}_w=\mathbf{U}\mathbf{\Sigma}\mathbf{V}^{\mathrm T}\\ \mathbf{S}_w^{-1}=\mathbf{V}\mathbf{\Sigma}^{-1}\mathbf{U}^{\mathrm T} $$
代入np.linalg.svd返回值:
$$ \mathbf{cov}=\mathbf{U}\mathbf{S}\mathbf{V}\\ \mathbf{cov}^{-1}=\mathbf{V}^{\mathrm T}\mathbf{S}^{-1}\mathbf{U}^{\mathrm T} $$
u, s, v = np.linalg.svd(cov, full_matrices=False) inv = np.matmul(v.T * 1 / s, u.T) |
相关知识: svd(), 酉矩阵
SVD
总共有三个返回值u,s,v
u大小为(M,M),s大小为(M,N),v大小为(N,N)。
其中s是对矩阵a的奇异值分解。s除了对角元素不为0,其他元素都为0,并且对角元素从大到小排列。s中有n个奇异值,一般排在后面的比较接近0,所以仅保留比较大的r个奇异值。
full_matrices默认值为1,这时u的大小为(M,M),v的大小为(N,N) 。否则u的大小为(M,K),v的大小为(K,N) ,K=min(M,N)。
https://blog.csdn.net/rainpasttime/article/details/79831533
酉矩阵
U^T*U=I, m阶酉矩阵(unitary matrix); V^T*V=I, n阶酉矩阵.
酉矩阵: 共轭转置为其逆矩阵. 实正交表示是幺正表示的特例.
U^T*U=U* U^T =I_n,其中I_n为n阶单位方阵,U^T为U的共轭转置矩阵, 则称U为酉矩阵。
https://blog.csdn.net/linkequa/article/details/88714735
计算weights和bias解析解
详见分类一节的后验概率分析.
$$ P\left( C_{1} \middle| x \right) = \sigma\left( z \right) = \sigma\left( {w \cdot x + b} \right) \\ If~P\left( C_{1} \middle| x \right) > 0.5,~x~belongs~to~class~1~\left( Water \right) $$
其中参数:
$$ w^T=\left( {\mu^{1} - \mu^{2}} \right)^{T}\Sigma^{- 1} \\ b=- \frac{1}{2}\left( \mu^{1} \right)^{T}\Sigma^{- 1}\mu^{1} + \frac{1}{2}\left( \mu^{2} \right)^{T}\Sigma^{- 1}\mu^{2} + ln\frac{N_{1}}{N_{2}} $$
由于y=0的含义是类2, 所以此处mean0-mean1即代表μ2-μ1. 相当于代公式代反了.
本来是:
y | 类 |
1 | 1 |
0 | 2 |
当成了
y | 类 |
1 | 2 |
0 | 1 |
# 直接计算weights和bias w = np.dot(mean_0 - mean_1, inv)#此处inv·μ=μ·inv b = (-0.5) * np.dot(mean_0, np.dot(inv, mean_0)) + 0.5 * np.dot(mean_1, np.dot(inv, mean_1))\ + np.log(float(X_train_0.shape[0]) / X_train_1.shape[0]) #矩阵与向量进行运算时,向量会进行自动转置操作 |
相关知识: 矩阵与向量相乘的几种组合
https://www.jb51.net/article/178703.htm
预测测试集标签
predictions = 1 - _predict(X_test, w, b) #由于公式代反了, 所以预测出的类和对率回归相反. 用1 -调整过来 |
对比两个模型y值与类对应关系
对率回归:
概率生成:
P->1为C1, 反之P->0为C2
得到最显著特征:
Retail trade 8.60693359375 94 -6.8515625 34 -6.46533203125 37 -5.9384765625 Other service -5.5498046875 47 -5.0927734375 Private household services -5.083984375 33 5.01611328125 Mining 4.80029296875 Construction 4.4775390625 |
Report题目
1. 生成式/判别模型对比
請比較實作的 generative model 及 logistic regression 的準確率,何者較佳? 請解釋為何有這種情況?
对率回归:
Training accuracy: 0.8836166291214418
Development accuracy: 0.8733873940287504
testing accuracy: 0.88617
概率生成:
Training accuracy: 0.8704106458271896
testing accuracy: 0.87937
对率回归的表现更好, 因为对率回归没有对概率分布做任何实质性的假设(推导过程中的假设只是便于理解和计算,对实际结果没有影响). 生成式模型假设样本呈高斯分布.
2. 正则化
請實作 logistic regression 中weight和bias的正規化 (regularization),並討論其對於你的模型準確率的影響。接著嘗試對正規項使用不同的權重 (lambda),並討論其影響。(有關 regularization 請參考 https://goo.gl/SSWGhf中的p.35. 也就是回归这一节课的PPT)
尝试调整原模型参数.
原本模型中的参数除了迭代次数可稍大些, batch_size, 学习率, 貌似都没收到什么好结果.
max_iter = 20 batch_size = 8 learning_rate = 0.2 |
Training loss: 0.29900114417375984 Development loss: 0.27995328925251284 Training accuracy: 0.8846026245945149 Development accuracy: 0.8800221157390343 |
加入正则化
原损失函数
对于训练集(𝑥^𝑛,𝑦 hat^𝑛 )
𝑦 hat^𝑛: 1-class 1, 0-class 2
$$ L\left( f \right) = {\sum_{n}{l\left( {f\left( x^{n} \right),{\hat{y}}^{n}} \right)}} \\=\sum_{n} - \left\lbrack {{\hat{y}}^{n}lnf\left( x^{n} \right) + \left( {1 - {\hat{y}}^{n}} \right) ln\left( {1 - f\left( x^{n} \right)} \right)} \right\rbrack $$
损失函数为所有样本点的output(即f)和实际target(y hat)在Bernoulli distribution(两点分布)下的交叉熵总和
线性回归损失函数正则化
原来的损失函式只考虑了预测的误差, 加一项考虑w大小(𝜆∑(𝑤_𝑖 )^2),但不用考虑bias, bias与平滑程度无关.
$$ L = \sum_{n} ( \hat{y}^n – ( b + w*x_{cp}^n ) )^2 + \lambda \sum ( w_i )^2 $$
期待参数的值更小的function, 意味着更平滑, 输出受输入影响更小, 当测试集的输入含噪声时, 平滑的函式受更小的影响. λ越高越平滑, 在训练集上得到的误差越大,但是在测试集上先减小后增加.
对率回归损失函数正则化
$$ L\left( f \right) = {\sum_{n}{l\left( {f\left( x^{n} \right),{\hat{y}}^{n}} \right)}}+ \lambda \sum ( w_i )^2 \\=\sum_{n} - \left\lbrack {{\hat{y}}^{n}lnf\left( x^{n} \right) + \left( {1 - {\hat{y}}^{n}} \right) ln\left( {1 - f\left( x^{n} \right)} \right)} \right\rbrack+ \lambda \sum ( w_i )^2 $$
这个w为data_dim维向量d*1
正则化梯度下降更新公式
参考:
https://www.cnblogs.com/richqian/p/4514528.html
https://blog.csdn.net/kamidox/article/details/50044445
$$ \begin{align} w_i & = w_i - \eta \frac\partial{\partial{w_i}}L(w) \\ & = w_i - \eta \left[ \frac{1}{m} \sum_{n=1}^m \left( f_w(x^{(n)}) - y^{(n)} \right) x_i^{(n)} + \frac{\lambda}{m} w_i \right] \\ & = w_i (1 - \eta \frac{\lambda}{m}) - \eta \frac{1}{m} \sum_{n=1}^m \left(\left(f(x^{(n)}) - y^{(n)}\right) x_i^{(n)}\right) \end{align} $$
在代入损失函数后, 更新公式经过损失函数对wi偏微分, 其中的Σ和平方都不见了, 退化回了wi. 还好查了一下, 和自己用损失函数瞎代的结果完全不一样.
找参考资料之前的碎碎念:
这个更新公式左侧计算结果是wi, 实际应用时是左侧也为一个w向量, 右侧也是. 是否应该考虑其他维度的w? 此处是把所有权重内积当作损失了, 认为是要看的.
正则项也随事件减少比较合适? pred_error, X.T形状分别是8, (510,8). 其中pred_error的维度对应的是一个小批次batch_size样本个数. w^2应有的形状应该与之相同. 考虑向量所有项加同一个标量.
w = w*(1-(learning_rate/np.sqrt(step))*regularization_weight) - learning_rate/np.sqrt(step) * w_grad |
正则参数λ影响
参数设置参考:
https://blog.csdn.net/manong_wxd/article/details/78734856
λ=1时结果: Training accuracy: 0.8706328077001844 Development accuracy: 0.8632510136380391 |
λ=0.1 Training accuracy: 0.880252875258036 Development accuracy: 0.8754146701068928 |
λ=0.05 Training accuracy: 0.8827226481863757 Development accuracy: 0.8792849244378916 |
λ=0.005 Training accuracy: 0.882814803892657 Development accuracy: 0.8814964983413196 |
λ=0.0005 Training accuracy: 0.8832202890002949 Development accuracy: 0.8767047548838923 |
λ=0.005终于有一点点提升, 最后提交testing accuracy: 0.88806
不同权重lambda的影响: 过大的lambda会严重影响结果, 可能原因为造成的偏差过大. 当lambda减小的过程中, 精度会先上升后下降, 最后趋近于正则化之前的结果.
3. 训练方式
請說明你實作的 best model,其訓練方式和準確率為何?
训练方式为对率回归, 准确率0.88806.
4. 特征标准化
請實作輸入特徵標準化 (feature normalization),並比較是否應用此技巧,會對於你的模型有何影響。
特征标准化之前已经做过了, 在数据准备阶段:
对训练集测试集的X做标准化normalize.
if train: X_mean = np.mean(X[:, specified_column] ,0).reshape(1, -1)#reshape(1,-1)转换为行数1, 列数根据行数计算 X_std = np.std(X[:, specified_column], 0).reshape(1, -1) X[:,specified_column] = (X[:, specified_column] - X_mean) / (X_std + 1e-8)#(x-μ)/σ |
X_train, X_mean, X_std = _normalize(X_train, train = True) X_test, _, _= _normalize(X_test, train = False, specified_column = None, X_mean = X_mean, X_std = X_std)#'_'做变量名合法, 作为无用的临时变量 |
特征标准化原理
关于理论部分可参考第一次作业:
https://www.kaggle.com/laugoon/homework1#Normalize-(1)
Normalize
预处理数据有一个很关键的步骤就是数据的标准化. 许多学习算法中目标函数的基础都是假设所有的特征都是零均值并且具有同一阶数上的方差。如果某个特征的方差比其他特征大几个数量级,那么它就会在学习算法中占据主导位置,导致学习器并不能像我们说期望的那样,从其他特征中学习。
Normalize方法1 StandardScaler:
标准化数据通过减去均值然后除以方差(或标准差),这种数据标准化方法经过处理后数据符合标准正态分布,即均值为0,标准差为1.
由于接触到的相似名词比较多, 查了一些资料做扩展.
这篇文章谈到Scaling与Normalization的区别:
https://www.jianshu.com/p/e8432fd5ab22
(引自e8432fd5ab22)特征缩放,特点是不改变数据分布情况。比如min-max或者Z-score. Normalization则会改变数据的分布。比如Box-Cox转换,可以将数据转为正态分布.
但上篇(e8432fd5ab22)中的Scaling恰是下篇(105477848)中说的Normalization:
https://blog.csdn.net/iteapoy/article/details/105477848
真是让人迷惑的世界…
(引自105477848)Normalization和Standardization分别被翻译成归一化和标准化,其实是有问题的,很容易被混淆。实际上,两者可以统称为标准化(Normalization).
z-score:
$$ x =\frac{x-\mu}{\sigma} $$
min-max:
$$ x=\frac{x-x_{min}}{x_{max}-x_{min}} $$
这两篇比较详细靠谱: https://www.freesion.com/article/6450332900/
https://blog.csdn.net/weixin_37947156/article/details/99065938
对于神经元的激活值来说,不论哪种Normalization方法,其规范化目标都是一样的,就是将其激活值规整为均值为0,方差为1的正态分布.
对模型影响
取消对輸入特徵標準化, 查看模型训练情况.
Training loss: 3.7869562801147327 Development loss: 3.7779240363858566 Training accuracy: 0.7850706532869138 Development accuracy: 0.7858459270180612 |
可以看到准确率有明显下降.
不进行标准化对模型训练的影响: 如果某个特征的方差比其他特征大几个数量级,那么它就会在学习算法中占据主导位置,导致学习器并不能像我们说期望的那样,从其他特征中学习。另外, 在梯度下降的过程中, 其误差曲面在w1方向平滑, 在w2方向陡峭. 两个方向需要非常不同的学习率. 而其参数移动方向顺着等高线法线(梯度)方向, 并不指向圆心.
(详细可参考梯度下降一节的笔记
https://blog.csdn.net/lagoon_lala/article/details/116212939)