机器学习的本质:利用数据去解决问题
数据预处理(在深度学习部分很重要)->训练阶段->模型生成->预测阶段
我们通常会选择一部分数据作为测试集,比如20%左右。
有时还会多出一个20%左右的验证集
在此过程中,预测模型会被不断改进和使用
再进一步细分,机器学习的步骤为:
收集数据->数据预处理->选择模型->训练->评估->超参数调整->预测
评价机器学习好坏的指标:损失函数loss
对于“区域”这类特征,需要进行one-hot编码、标签编码等将其进行离散化编码。
对于非数值类型[字符串等等]的数据元,常常使用标签编码将其转化.
比如:海淀、通州、朝阳分别对应着数值1,2,3.
机器学习常常有很多特征,基于这些特征,我们需要训练在Model中的权重w,这些特征值构成的特征,称之为权重矩阵Weights,同时还存在着偏biases。
import numpy as np
import matplotlib.pyplot as plt
#MAE损失函数
def MAE_loss(y,y_hat):
return np.mean(np.abs(y_hat - y))
#MSE损失函数
def MSE_loss(y,y_hat):
return np.mean(np.square(y_hat - y))
#线性回归
def linear(x,k,b):
y = k * x + b
return y
if __name__ == '__main__':
x = np.array([50,80,100,200])
y = np.array([82,119,172,302])
plt.scatter(x,y)
#初始化最小损失函数值
min_loss = float('inf')
#暴力穷举方式
for k in np.arange(-2,2,0.1):
for b in np.arange(-10,10,0.1):
#计算预测值
y_hat = [linear(xi,k,b) for xi in list(x)]
#计算损失函数
current_mae_loss = MAE_loss(y,y_hat)
#记录损失函数最小时的k和b
if current_mae_loss < min_loss:
min_loss = current_mae_loss
best_k,best_b = k,b
#print('mae:{}'.format(current_mae_loss))
print("best k:{},best b:{}".format(best_k,best_b))
y_hat = best_k * x + best_b
plt.plot(x,y_hat,color='red')
plt.grid()
plt.show()
结果:
#采用批量梯度下降方法
import numpy as np
import matplotlib.pyplot as plt
#平均绝对误差
def MAE_loss(y,y_hat):
return np.mean(np.abs(y_hat - y))
#均方误差
def MSE_loss(y,y_hat):
return np.mean(np.square(y_hat - y))
def linear(x,k,b):
return k * x + b
#gradient of k
def gradient_k(x,y,y_hat):
n = len(y)
gradient = 0
for xi,yi,yi_hat in zip(list(x),list(y),list(y_hat)):
gradient += (yi_hat - yi) * xi
return gradient / n
#gradient of b
def gradient_b(y,y_hat):
n = len(y)
gradient = 0
for yi,yi_hat in zip(list(y),list(y_hat)):
gradient += (yi_hat - yi)
return gradient / n
if __name__ == '__main__':
#初始数据
x = np.array([50,80,100,200])
y = np.array([82,119,172,302])
plt.scatter(x,y)
plt.grid()
#数据预处理
max_x = np.max(x)
max_y = 1
x = x / max_x
y = y / max_y
#初始化参数
times = 1000 #迭代次数
min_loss = float('inf') #最小损失函数值
current_k = 10
current_b = 10
learn_rate = 0.1
#开始迭代
for i in range(times):
y_hat = [linear(xi,current_k,current_b) for xi in list(x)]
current_loss = MSE_loss(y,y_hat)
if current_loss < min_loss:
min_loss = current_loss
best_k,best_b = current_k,current_b
print('best_k :{},best_b :{}'.format(best_k,best_b))
#计算梯度
k_gradient = gradient_k(x,y,y_hat)
b_gradient = gradient_b(y,y_hat)
#更新权重
current_k = current_k - learn_rate * k_gradient
current_b = current_b - learn_rate * b_gradient
best_k = best_k / max_x * max_y
best_b = best_b / max_x * max_y
print(best_k,best_b)
x = x * max_x
y = y * max_y
plt.plot(x,y_hat,color='red')
plt.scatter(x,y)
plt.grid()
plt.show()
训练过程:
机器学习的过程,就是在搜索空间中对w和b进行搜索的过程,使得模型的准确率达到某个标准。一次训练,称为一次迭代,目的就是更新权重和变量,经过不断地迭代,使得模型中的参数不断进行更新,当训练完成时,就可以用该模型对房价进行预测。
什么是回归问题?什么是分类问题?
回归问题其实就是实数的求解问题,分类问题是离散问题。
判断方法:输出的数据类型,离散or连续
什么是线性回归,什么是逻辑回归?
线性回归解决的是回归问题。逻辑回归解决的是分类问题,是分类算法[利用
sigmod
函数]
loss = bias + variance
误差的期望值 = 噪音的方差 + 模型预测值的方差 + 预测值相对真实值的偏差的平方
偏差:
偏差反映的是模型再样本上的输出与真实值之间的误差。
如何降低?
- 增加算法的复杂度
例如:线性回归增加参数个数来提高模型的复杂度;神经网络通过增加隐单元个数来提高模型的复杂度。- 优化输入的特征->增加更多的特征
- 削弱或者去除已有的正则化约束 => 可能增加方差
- 调整模型结构
方差:
方差越大的模型越容易过拟合。
对于方差大,过拟合的情况:
- 增加训练集的数据量,不会影响偏差。
- 正则化,模型过于偏向正则项可能影响偏差
- 使用多种模型训练数据,采用交叉验证等方式选取最终模型
正则化:
为了降低模型复杂度。
sigmoid
特点:
如果初始化神经网络的权值为 [0,1] 之间的随机值,由反向传播算法可知,梯度从后向前传播时,每传递一层梯度值都会减小为原来的0.25倍。如果神经网络层数多,那么梯度在多层传播后将变得很小(接近于0),即梯度消失
当网络权值初始化为 (1,+∞) 区间内的值,则会出现梯度爆炸
tanh:
- 相比于sigmoid函数,tanh的均值是0
- tanh相比于Sigmoid函数更容易训练,具有优越性
- 用于归一化回归问题,其输出在[-1,1]范围内。通常与L2损失一起使用
单侧抑制,ReLU实现稀疏后的模型能够更好地挖掘相关特征,拟合训练数据
对于线性函数而言,ReLU的表达能力更强,尤其体现在深度网络中
而对于非线性函数而言,ReLU由于非负区间的梯度为常数,因此不存在梯度消失问题,使得模型的收敛速度维持在一个稳定状态
综上:
- sigmoid和tanh函数输出值在(0,1)和(-1,1)之间 => 适合处理概率值;会产生梯度消失 => 不适合深层网络训练
- relu的有效导数是常数1,解决了深层网络中出现的梯度消失问题 => 更适合深层网络训练
为什么需要在神经网络中使用非线性激活函数?
定义网络结构(指定输出层、隐藏层、输出层的大小)
初始化模型参数
循环操作:
3.1 执行前向传播
3.2 计算损失函数
3.3 执行后向传播
3.4 权值更新
权重矩阵的作用
import numpy as np
import matplotlib.pyplot as plt
if __name__ == '__main__':
#n:样本大小;d_in:输入维度;h:隐藏层维度;d_out:输出维度
n,d_in,h,d_out = 64,1000,100,10
#随机生成数据
x = np.random.randn(n,d_in) # n行d_in列,具有标准正态分布
y = np.random.randn(n,d_out) # n行d_out列,具有标准正态分布
#print(x)
#随机初始化权重
w1 = np.random.randn(d_in,h) #输入层到隐藏层权重
w2 = np.random.randn(h,d_out) #隐藏层到输出层权重
#设置学习率
learn_rate = 1e-6
#迭代次数
times = 200
for i in range(times):
#前向传播 计算预测值y
temp = x.dot(w1)
temp_relu = np.maximum(temp,0) #逐元素比较两个array的大小,小于0为0
y_pred = temp_relu.dot(w2)
#计算损失函数
loss = np.square(y_pred - y).sum() / n
print(i,loss)
#反向传播
grad_y_pred = 2.0 * (y_pred - y)
#计算w2梯度
grad_w2 = temp_relu.T.dot(grad_y_pred)
grad_temp_relu = grad_y_pred.dot(w2.T)
grad_temp = grad_temp_relu.copy()
#relu激活函数,小于0为0
grad_temp[temp < 0] = 0
#计算w1梯度
grad_w1 = x.T.dot(grad_temp)
#更新权重
w1 -= learn_rate * grad_w1
w2 -= learn_rate * grad_w2
print(w1,w2)
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston
from sklearn.utils import shuffle, resample
# relu函数
def Relu(x):
res = np.where(x < 0,0,x)
return res
# 定义损失函数
def MSE_loss(y, y_hat):
return np.mean(np.square(y_hat - y))
# 定义线性回归函数
def Linear(X, W1, b1):
y = X.dot(W1) + b1
return y
if __name__ == '__main__':
#数据加载
data = load_boston()
X_ = data['data']
y = data['target']
#将y转化为矩阵的形式
y = y.reshape(y.shape[0],1) #shape[0]读取第0维长度 reshape:修改为指定维度大小
#数据规范化 axis = 0:压缩行,对各列求均值,返回1*n的矩阵
X_ = (X_ - np.mean(X_,axis=0)) / np.std(X_,axis=0)
"""
初始化网络参数
定义隐藏层维度n_hidden,w1,b1,w2,b2
"""
n_features = X_.shape[1] #获取列的维度大小,即特征数
n_hidden = 10
w1 = np.random.randn(n_features, n_hidden)
b1 = np.zeros(n_hidden)
w2 = np.random.randn(n_hidden, 1)
b2 = np.zeros(1)
# 设置学习率
learning_rate = 1e-6
# 5000次迭代
for t in range(5000):
# 前向传播,计算预测值y (Linear->Relu->Linear)
l1 = Linear(X_,w1,b1)
s1 = Relu(l1)
y_pred = Linear(s1,w2,b2)
# 计算损失函数, 并输出每次epoch的loss
loss = MSE_loss(y,y_pred)
# 反向传播,基于loss 计算w1和w2的梯度
grad_y_pred = 2 *(y_pred - y)
grad_w2 = s1.T.dot(grad_y_pred)
grad_temp_relu = grad_y_pred.dot(w2.T)
grad_temp_relu[l1 < 0] = 0
grad_w1 = X_.T.dot(grad_temp_relu)
# 更新权重, 对w1, w2, b1, b2进行更新
w1 = w1 - learning_rate * grad_w1
w2 = w2 - learning_rate * grad_w2
# 得到最终的w1, w2
print('w1={} \n w2={}'.format(w1, w2))
from sklearn.datasets import make_moons
import torch
import numpy as np
import matplotlib.pyplot as plt
import torch.nn as nn
import torch.nn.functional as F
from sklearn.metrics import accuracy_score
#定义网络模型,继承nn.Module
class Net(nn.Module):
#初始化
def __init__(self):
super(Net,self).__init__()
#定义第一个FC层,使用Linear transformation
self.fc1 = nn.Linear(2,100)
#定义第二个FC层,使用Linear transformation
self.fc2 = nn.Linear(100,2)
#前向传播
def forward(self,x):
#第一层输出
x = self.fc1(x)
#激活层
x = torch.tanh(x)
#输出层
x = self.fc2(x)
return x
#预测结果
def predict(self,x):
pred = self.forward(x)
ans = []
for t in pred:
if t[0] > t[1]:
ans.append(0)
else:
ans.append(1)
return torch.tensor(ans)
# 进行预测,并转换为numpy类型
def predict(x):
x = torch.from_numpy(x).type(torch.FloatTensor)
ans = model.predict(x)
return ans.numpy()
# 绘制二分类决策面
def plot_decision_boundary(pred_func, X, y):
# Set min and max values and give it some padding
x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() + .5
y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() + .5
h = 0.01
# 计算决策面
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
# np.c_按行连接两个矩阵,就是把两矩阵左右相加
Z = pred_func(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
# 绘制分类决策面
plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral)
# 绘制样本点
plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.binary)
plt.show()
if __name__ == '__main__':
# 使用make_moon内置生成模型,随机产生二分类数据,200个样本
np.random.seed(33)
X,y = make_moons(200,noise=0.2)
print(y)
cm = plt.cm.get_cmap('RdYlBu')
#X[:,0]:所有数组中取第0个数据 X[:,1]:所有数组中取第1个数据
plt.scatter(X[:,0],X[:,1],s=40,c=y,cmap=cm)
plt.show()
#数组转换成张量,且二者共享内存
X = torch.from_numpy(X).type(torch.FloatTensor)
y = torch.from_numpy(y).type(torch.LongTensor)
#初始化模型
model = Net()
#定义评估标准
criterion = nn.CrossEntropyLoss()
#定义优化器
print(f'\nParameters: {np.sum([param.numel() for param in model.parameters()])}')
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
#迭代次数
times = 1000
#存储每次迭代的loss
losses = []
for i in range(times):
#对输入的x进行预测
y_pred = model.forward(X)
#得到损失函数
loss = criterion(y_pred,y)
losses.append(loss.item())
#清空之前的梯度
optimizer.zero_grad()
#计算梯度
loss.backward()
#调整权重
optimizer.step()
print(model.predict(X))
print(accuracy_score(model.predict(X), y))
plot_decision_boundary(lambda x: predict(x), X.numpy(), y.numpy())