基础
反向传播的原理是计算图,是对函数求偏导,只有一条支路的直接相乘,有两条支路的要进行相加。
线性模型
构建神经网络的过程:
- 寻找所需的数据集,数据集分为训练集和测试集,训练集又分为训练集和开发集
- 建立神经网络模型:y=f(x)
- 训练数据集
- 对新的数据进行推理
人工进行训练:人工选择权重
泛化能力:即对模型训练完后,对新的图像也可以正确识别的能力
求损失函数的最小值,损失函数是预测值减去真实值的平方值,越小说明模型的泛化能力越好,MSE即平均平凡误差,用来在一个数据集中求损失值
用穷举法选取权重值
import torch
import numpy as np
import matplotlib.pyplot as plt
x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]
def forward(x):
return x*w
def loss(x,y):
y_pred = forward(x)
return (y_pred-y)*(y_pred-y)
w_list = []
mse_list = []
for w in np.arange(0.0,4.1,0.1):
print('w',w)
l_sum = 0
for x_val,y_val in zip(x_data,y_data):
y_pred_val = forward(x_val)
loss_val = loss(x_val,y_val)
l_sum += loss_val
print('\t',x_val,y_val,y_pred_val,loss_val)
print('MSE',l_sum/3)
w_list.append(w)
mse_list.append(l_sum/3)
plt.plot(w_list,mse_list)
plt.ylabel('Loss')
plt.xlabel('w')
plt.show()
Visdom 可视化工具
要定期存盘,输出日志,可视化显示数据
过拟合
过度拟合是深度学习中经常出现的问题,是由于拟合函数过度拟合数据样本而出现的问题。解决方式有以下方法:
- 增加数据量
- 运用正规化,增加惩罚机制,通过cost调整w的值
- dropout 随机的抛弃一些神经元和神经之间的连接,让不完整的神经网络进行训练
注意:在前向传播时可以使用dropout屏蔽掉一些神经元,但是在预测时要将dropout功能去除掉
梯度下降算法的实现
分治法:目标函数是凸函数时会有比较好的结果,如果目标函数比较曲折,会出现错误
优化问题:指求目标函数的最小值
用贪心算法和梯度下降的算法不一定能得到最优的结果,但是可以得到局部范围内最优的结果。
a:为学习率,即梯度下降的速度
鞍点:在神经网络迭代过程中,很少的权重值会陷入局部最优,最重要的是解决鞍点的问题
import torch
import numpy as np
import matplotlib.pyplot as plt
x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]
w = 1.0
def forward(x):
return x*w
def cost(xs,ys):
cost = 0
for x,y in zip(xs,ys):
y_pred = forward(x)
cost += (y_pred-y)**2
return cost/len(xs)
def gradient(xs,ys):
grad = 0
for x,y in zip(xs,ys):
grad += 2*x*(x*w-y)
return grad/len(xs)
print('Predict (before training)',4,forward(4))
for epoch in range(100):
cost_val = cost(x_data,y_data)
grad_val = gradient(x_data,y_data)
w -= 0.01*grad_val
print("Epoch:",epoch,'w=',w,'loss=',cost_val)
print('Predict(after training)',4,forward(4))
训练失败的原因:
- 学习率a取很大,尝试减小学习率进行训练
随机梯度下降:即随机的选择一个loss值,计算梯度值,可以有效的避免出现鞍点的问题。
改为随机梯度后的代码:
import torch
import numpy as np
import matplotlib.pyplot as plt
x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]
w = 1.0
def forward(x):
return x*w
def loss(x,y):
y_pred = forward(x)
return (y_pred-y)**2
def gradient(x,y):
return 2*x*(x*w-y)
print('Predict (before training)',4,forward(4))
for epoch in range(100):
for x,y in zip(x_data,y_data):
grad = gradient(x,y)
w = w-0.01*grad
print('\tgrad:',x,y,grad)
l = loss(x,y)
print('progress:',epoch,'w=',w,'loss',l)
print('Predict(after training)',4,forward(4))
batch:分批读取和处理数据
随机梯度算法的性能高,时间复杂度也高,即耗费的时间长
梯度算法的性能低,时间复杂度也较低
反向传播
矩阵计算的书:matrix-cook-book
链式法则:
- 先创建计算图
创建计算图的具体方法:
梯度的值不会清零,要进行手动清零
import torch
x_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]
w = torch.Tensor([1.0])
#默认情况下不会计算梯度,设置为true会计算梯度
w.requires_grad = True
#将x转换为tensor形式,与w进行数乘
def forward(x):
return x*w
def loss(x,y):
y_pred = forward(x)
return (y_pred-y)**2
print('predict (before traning)',4,forward(4).item())
for epoch in range(100):
#sum = 0
for x,y in zip(x_data,y_data):
#l 是一个张量,即tensor,张量计算时会出现计算图,单混的数值计算要避免使用张量
l = loss(x,y)
#会计算整个反向传播过程中的w,并把值保存到w中
l.backward()
#提取数据用.item()
print('\tgrad:',x,y,w.grad.item())
#数值计算要使用.data
w.data = w.data-0.01*w.grad.data
#sum += l.item() 用sum进行加减时不能直接使用sum+=1,L是张量,一直计算会造成内存不够,要死hi用L.item()
w.grad.data.zero_()
print('progress:',epoch,l.item())
print('predict (after training)',4,forward(4).item())
用pytorch实现线性模回归
- 确定模型
- 优化目标:定义损失函数(标量)sgd 随机梯度下降 求权重
用pytorch构建神经网络 - 准备数据
- 设计模型
- 构造损失函数和优化器
- 写训练周期,前馈-反馈-更新
数据进行准备时,要将数据变为统一的矩阵类型,用numpy的广播功能可以实现:
loss一定要标量,否则不能进行反向传播
构建损失函数:
构建优化器:
训练:
测试:
全部代码:
import torch
#准备数据
x_data = torch.Tensor([[1.0],[2.0],[3.0]])
y_data = torch.Tensor([[2.0],[4.0],[6.0]])
#定义神经网络模型
#nn.Module 可以自动进行反向传播
class LinearModel(torch.nn.Module):
def __init__(self):
super(LinearModel,self).__init__() #调用父类的构造函数
self.linear = torch.nn.Linear(1,1) #输入与输出的维度应相同
def forward(self,x):
y_pred = self.linear(x) #构造对象,包括w和b
return y_pred
model = LinearModel()
#定义损失函数与优化器
#size_average =False 表示不使用平均值 reduce 表示是否使用梯度
criterion = torch.nn.MSELoss(size_average =False)
#优化器的优化对象model->linear-> w,b lr是学习率
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
#训练
for epoch in range(1000):
#计算y hat
y_pred = model(x_data)
#计算loss值
loss = criterion(y_pred,y_data)
print(epoch,loss.item())
#将梯度归零
optimizer.zero_grad()
#反向传播
loss.backward()
#更新权重
optimizer.step()
#打印w的值
print('w=',model.linear.weight.item())
#打印b的值
print('b=',model.linear.bias.item())
x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('y_pred= ',y_test.data)