🎬个人简介:一个全栈工程师的升级之路!
📋个人专栏:pytorch深度学习
🎀CSDN主页 发狂的小花
🌄人生秘诀:学习的本质就是极致重复!
《PyTorch深度学习实践》完结合集_哔哩哔哩_bilibili
目录
1 多维数据的输入
注意bias使用矩阵的广播机制会复制多份,与输入维度相同
- 问题引入:
一个人是否患有糖尿病有多个指标x1,x2,x3,x4,x5...,患有糖尿病的结果有患和不患(1 和0)两种,因此这是一个有着多维输入的二分类问题。
下图横轴一维代表一个样本sample,纵轴[X]一维代表一个指标,深度学习中可以叫一个特征feature,[Y]是二分类的结果。
- 多维数据的引入说明:
- 构造计算图:8维到1维,矩阵乘加实现
- 激活层:
对于二分类问题,这里使用sigmod激活函数,一个sigmod本身是一个算子,对于sigmod等非线性算子优化的手段一般是线性拟合和查表,查表比较好。
- nn.Linear 原码理解
pytorch系列 ----暂时就叫5的番外吧: nn.Modlue及nn.Linear 源码理解
2 激活函数
机器学习中常用的几种函数--激活函数、损失函数_激活函数和损失函数的区别-CSDN博客
- 理解激活函数和损失函数:
Relu等激活函数是为了解决在反向传播中梯度消失问题,而cross-entropy loss是为训练网络进行分类的,这两者之间并没有直接的关联!
这里结合softmax可以很好的理解激活函数和损失函数,softmax一般在神经网络的最后一层,用于分类问题,虽然它可以作为激活函数,但是其不是为了改变输入值,因此一般不认为是激活函数。也就是说,损失函数的选择由它任务有关,即最后一层处理有关,与其整个网络中的激活函数无关,各自针对的问题不同,不可以混为一谈。
- 输出层的激活函数和损失函数由任务类型决定,见下表。它们与隐藏层的激活函数的选择是独立的。
3 问题解决
- 数据集建立:
(1)训练集,去掉压缩包内最后10组数据
(2)测试集,将最后10组数据作为测试集
- 建立Model和激活函数:
几个 Linera+sigmoid
- 损失函数和优化器
BCELoss+SGD 或者 BCELoss+Adam
- 训练:
主要是学习率的设置,SGD的训练速度和收敛与学习率有很大的关系;Adam需要设置初始的学习率,中间会自动调整学习率。
- SGD 训练100万epoch,学习率设置0.1 结果如下:
import numpy as np
import torch
import matplotlib.pyplot as plt
# prepare dataset
xy = np.loadtxt('./dataset/diabetes_train.csv.gz', delimiter=',', dtype=np.float32)
x_data = torch.from_numpy(xy[:, :-1]) # 第一个‘:’是指读取所有行,第二个‘:’是指从第一列开始,最后一列不要
print("input data.shape", x_data.shape)
y_data = torch.from_numpy(xy[:, [-1]]) # [-1] 最后得到的是个矩阵
xy_test = np.loadtxt('./dataset/diabetes_test.csv.gz', delimiter=',', dtype=np.float32)
x_data_test = torch.from_numpy(xy_test[:, :-1]) # 第一个‘:’是指读取所有行,第二个‘:’是指从第一列开始,最后一列不要
print("input data.shape", x_data_test.shape)
y_data_test = torch.from_numpy(xy_test[:, [-1]]) # [-1] 最后得到的是个矩阵
# print(x_data.shape)
# design model using class
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = torch.nn.Linear(8, 6)
self.linear2 = torch.nn.Linear(6, 4)
self.linear3 = torch.nn.Linear(4, 2)
self.linear4 = torch.nn.Linear(2, 1)
self.active = torch.nn.Sigmoid()
def forward(self, x):
x = self.active(self.linear1(x))
x = self.active(self.linear2(x))
x = self.active(self.linear3(x)) # y hat
x = self.active(self.linear4(x)) # y hat
return x
model = Model()
epoch_list = []
loss_list = []
# construct loss and optimizer
# criterion = torch.nn.BCELoss(size_average = True)
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
# training cycle forward, backward, update
for epoch in range(1000000):
y_pred = model(x_data)
loss = criterion(y_pred, y_data)
# print(epoch, loss.item())
epoch_list.append(epoch)
loss_list.append(loss.data.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
y_pred_label = torch.where(y_pred>=0.5,torch.tensor([1.0]),torch.tensor([0.0]))
acc = torch.eq(y_pred_label, y_data).sum().item()/y_data.size(0)
print("epoch: ",epoch,"loss = ",loss.item(), "acc = ",acc)
if (loss.item() < 1e-7):
break
pred_test_y = model(x_data_test)
test_pred_label = torch.where(pred_test_y>=0.9,torch.tensor([1.0]),torch.tensor([0.0]))
acc1 = torch.eq(test_pred_label, y_data_test).sum().item()/y_data_test.size(0)
print("acc test= ",acc)
plt.plot(epoch_list, loss_list)
plt.ylabel('loss')
plt.xlabel('epoch')
# plt.show()
plt.savefig('./data/pytorch6.png')
- Adam 训练1万epoch,初始学习率设置为0.01结果如下:
- 代码
import numpy as np
import torch
import matplotlib.pyplot as plt
# prepare dataset
xy = np.loadtxt('./dataset/diabetes_train.csv.gz', delimiter=',', dtype=np.float32)
x_data = torch.from_numpy(xy[:, :-1]) # 第一个‘:’是指读取所有行,第二个‘:’是指从第一列开始,最后一列不要
print("input data.shape", x_data.shape)
y_data = torch.from_numpy(xy[:, [-1]]) # [-1] 最后得到的是个矩阵
xy_test = np.loadtxt('./dataset/diabetes_test.csv.gz', delimiter=',', dtype=np.float32)
x_data_test = torch.from_numpy(xy_test[:, :-1]) # 第一个‘:’是指读取所有行,第二个‘:’是指从第一列开始,最后一列不要
print("input data.shape", x_data_test.shape)
y_data_test = torch.from_numpy(xy_test[:, [-1]]) # [-1] 最后得到的是个矩阵
# print(x_data.shape)
# design model using class
class Model(torch.nn.Module):
def __init__(self):
super(Model, self).__init__()
self.linear1 = torch.nn.Linear(8, 6)
self.linear2 = torch.nn.Linear(6, 4)
self.linear3 = torch.nn.Linear(4, 2)
self.linear4 = torch.nn.Linear(2, 1)
self.active = torch.nn.Sigmoid()
def forward(self, x):
x = self.active(self.linear1(x))
x = self.active(self.linear2(x))
x = self.active(self.linear3(x)) # y hat
x = self.active(self.linear4(x)) # y hat
return x
model = Model()
epoch_list = []
loss_list = []
# construct loss and optimizer
# criterion = torch.nn.BCELoss(size_average = True)
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
# training cycle forward, backward, update
for epoch in range(10000):
y_pred = model(x_data)
loss = criterion(y_pred, y_data)
# print(epoch, loss.item())
epoch_list.append(epoch)
loss_list.append(loss.data.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
y_pred_label = torch.where(y_pred>=0.5,torch.tensor([1.0]),torch.tensor([0.0]))
acc = torch.eq(y_pred_label, y_data).sum().item()/y_data.size(0)
print("epoch: ",epoch,"loss = ",loss.item(), "acc = ",acc)
if (loss.item() < 1e-7):
break
pred_test_y = model(x_data_test)
test_pred_label = torch.where(pred_test_y>=0.9,torch.tensor([1.0]),torch.tensor([0.0]))
acc1 = torch.eq(test_pred_label, y_data_test).sum().item()/y_data_test.size(0)
print("acc test= ",acc)
plt.plot(epoch_list, loss_list)
plt.ylabel('loss')
plt.xlabel('epoch')
# plt.show()
plt.savefig('./data/pytorch6.png')
4 SGD 和Adam优化器的比较
- 前言:
上述实验,我使用Adam前期可以比较迅速的收敛,使得loss收敛迅速,并且没有过拟合,一般Adam由于其特性出现过拟合的概率比SGD高。我用SGD优化器训练,训练了100万次才勉强达到Adam的1万次结果,由此可以看出Adam的收敛速度比SGD快很多,但是由于SGD的噪声比较大,而且其每次计算一个梯度或者一小批量的梯度,使得泛化能力强,适应于大型数据的训练中。
- 区别:
- SGD(随机梯度下降)
基本思想: SGD在每一步更新中仅使用一个(或一小批)样本来计算梯度,而不是使用整个数据集。这种方法可以显著减少计算量,使得训练大规模数据集变得可行。
学习率: SGD通常需要手动调整学习率,并且可能会使用如学习率衰减这样的技巧来帮助模型收敛。学习率的选择对SGD的性能影响很大。
收敛速度: SGD的收敛速度通常比较慢,尤其是在接近最小值的平坦区域。
泛化能力: 研究表明,由于SGD的噪声更大,它可能有助于模型找到泛化性能更好的解。
- Adam(自适应矩估计)
基本思想: Adam是一种自适应学习率的优化算法,它结合了动量(Momentum)和RMSprop的优点。Adam会为不同的参数计算不同的自适应学习率。
学习率: Adam自动调整学习率,通常不需要像SGD那样手动微调学习率,这使得Adam在很多情况下都能较快地收敛。
收敛速度: 由于自适应学习率的特性,Adam在初期训练阶段通常比SGD收敛得更快。
泛化能力: 尽管Adam在许多任务中都显示出了较快的收敛速度,但一些研究表明,对于某些问题,Adam可能导致过拟合,泛化能力不如SGD。
应用场景
Adam: 由于其易用性和快速收敛的特点,Adam非常适合在需要快速得到结果的场景中使用,特别是在计算资源有限或模型较复杂时。
SGD: 如果模型训练时出现过拟合,或者当你有足够的时间和资源来精细调整学习率时,SGD可能是更好的选择。对于大规模分布式训练,SGD的泛化能力可能更优。
总之,选择哪种优化算法取决于具体任务、模型的复杂性、可用的计算资源以及是否需要模型有更好的泛化能力。在实践中,可能需要尝试不同的优化算法,以找到最适合当前任务的选项。
🌈我的分享也就到此结束啦🌈
如果我的分享也能对你有帮助,那就太好了!
若有不足,还请大家多多指正,我们一起学习交流!
📢未来的富豪们:点赞👍→收藏⭐→关注🔍,如果能评论下就太惊喜了!
感谢大家的观看和支持!最后,☺祝愿大家每天有钱赚!!!欢迎关注、关注!