赞
踩
对于一个多维数据,其行表示一个样本,列表示样本的特征
对于多维特征的运算,实质上可以当做特征的映射
import torch import torch.nn.functional as F import numpy as np import matplotlib.pyplot as plt from sklearn import datasets xy=np.loadtxt('./data/Diabetes_class.csv.gz',delimiter=',',dtype=np.float32)#加载训练集合 x_data = torch.from_numpy(xy[:,:-1])#取前八列 y_data = torch.from_numpy(xy[:,[-1]])#取最后一列 test =np.loadtxt('./data/test_class.csv.gz',delimiter=',',dtype=np.float32)#加载测试集合,这里我用数据集的最后一个样本做测试,训练集中没有最后一个样本 test_x = torch.from_numpy(test) class Model(torch.nn.Module): def __init__(self):#构造函数 super(Model,self).__init__() self.linear1 = torch.nn.Linear(8,6)#8维到6维 self.linear2 = torch.nn.Linear(6, 4)#6维到4维 self.linear3 = torch.nn.Linear(4, 1)#4维到1维 self.sigmoid = torch.nn.Sigmoid()#因为他里边也没有权重需要更新,所以要一个就行了,单纯的算个数 def forward(self, x):#构建一个计算图,就像上面图片画的那样 x = self.sigmoid(self.linear1(x)) x = self.sigmoid(self.linear2(x))#将上面一行的输出作为输入 x = self.sigmoid(self.linear3(x)) return x model = Model()#实例化模型 criterion = torch.nn.BCELoss(size_average=False) #model.parameters()会扫描module中的所有成员,如果成员中有相应权重,那么都会将结果加到要训练的参数集合上 optimizer = torch.optim.SGD(model.parameters(),lr=0.1)#lr为学习率,因为0.01太小了,我改成了0.1 for epoch in range(1000): #Forward y_pred = model(x_data) loss = criterion(y_pred,y_data) print(epoch,loss.item()) #Backward optimizer.zero_grad() loss.backward() #update optimizer.step() y_pred = model(x_data) print(y_pred.detach().numpy()) y_pred2 = model(test_x) print(y_pred2.data.item())
# Training cycle
for epoch in range(training_epochs):
# Loop over all batches
for i in range(total_batch)
loadtxt适合读取 txt 和 csv 文件,默认读取float类型的值
numpy.loadtxt(
fname, dtype=, comments='#',
delimiter=None, converters=None,
skiprows=0, usecols=None,
unpack=False, ndmin=0)
可以自动进行小批量数据的生成
#in pcdet/datasets/__init__.py
dataloader = DataLoader(
dataset,
batch_size=batch_size,
num_workers=workers,
shuffle=True,
)
import torchvision
from torch.utils.data import DataLoader
'''
手写数字的数据集,其中训练集有60000个样本,测试集有10000个样本,共分为0-9,10个类
'''
train_set=torchvision.datasets.MNIST(root='./dataset/mnist',train=True,download=True)
test_set=torchvision.datasets.MNIST(root='./dataset/mnist',train=False,download=True)
train_loader=DataLoader(dataset=train_set,batch_size=32,shuffle=True)
test_loader=DataLoader(dataset=test_set,batch_size=32,shuffle=False)
import torch import numpy as np from torch.utils.data import Dataset from torch.utils.data import DataLoader ''' Dataset是一个抽象函数,不能直接实例化,所以我们要创建一个自己类,继承Dataset 继承Dataset后我们必须实现三个函数: __init__()是初始化函数,之后我们可以提供数据集路径进行数据的加载 __getitem__()帮助我们通过索引找到某个样本,下标操作 __len__()帮助我们返回数据集大小 DataLoader对数据集先打乱(shuffle),然后划分成mini_batch。 ''' class DiabetesDataset(Dataset): def __init__(self,filepath): xy = np.loadtxt(filepath,delimiter=',',dtype=np.float32) #shape本身是一个二元组(x,y)对应数据集的行数和列数,这里[0]我们取行数,即样本数 self.len = xy.shape[0] self.x_data = torch.from_numpy(xy[:, :-1]) self.y_data = torch.from_numpy(xy[:, [-1]]) def __getitem__(self, index): return self.x_data[index],self.y_data[index] def __len__(self): return self.len #定义好DiabetesDataset后我们就可以实例化他了 dataset = DiabetesDataset('./data/Diabetes_class.csv.gz') #我们用DataLoader为数据进行分组,batch_size是一个组中有多少个样本,shuffle表示要不要对样本进行随机排列 #一般来说,训练集我们随机排列,测试集不。num_workers表示我们可以用多少进程并行的运算 train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=2) class Model(torch.nn.Module): def __init__(self):#构造函数 super(Model,self).__init__() self.linear1 = torch.nn.Linear(8,6)#8维到6维 self.linear2 = torch.nn.Linear(6, 4)#6维到4维 self.linear3 = torch.nn.Linear(4, 1)#4维到1维 self.sigmoid = torch.nn.Sigmoid()#因为他里边也没有权重需要更新,所以要一个就行了,单纯的算个数 def forward(self, x):#构建一个计算图,就像上面图片画的那样 x = self.sigmoid(self.linear1(x)) x = self.sigmoid(self.linear2(x)) x = self.sigmoid(self.linear3(x)) return x model = Model()#实例化模型 criterion = torch.nn.BCELoss(size_average=False) #model.parameters()会扫描module中的所有成员,如果成员中有相应权重,那么都会将结果加到要训练的参数集合上 optimizer = torch.optim.SGD(model.parameters(),lr=0.1)#lr为学习率 if __name__=='__main__':#if这条语句在windows系统下一定要加,否则会报错 for epoch in range(1000): for i,data in enumerate(train_loader,0):#取出一个bath # repare data inputs,labels = data#将输入的数据赋给inputs,结果赋给labels #Forward y_pred = model(inputs) loss = criterion(y_pred,labels) print(epoch,loss.item()) #Backward optimizer.zero_grad() loss.backward() #update optimizer.step()
批量梯度下降、随机梯度下降和小批量梯度下降详解
在前面的学习中,前向传播是为了计算损失函数,而后向传播是为了更新各种的参数,在线性回归中,常用梯度下降来更新参数。
这里假设有数据 X = [ [ x 1 1 , x 2 1 ] , [ x 1 2 , x 2 2 ] , … … , [ x 1 n , x 2 n ] ] n × 2 X=[[x_1^1,x_2^1],[x_1^2,x_2^2],……,[x_1^n,x_2^n]]_{n×2} X=[[x11,x21],[x12,x22],……,[x1n,x2n]]n×2, y = [ [ y 1 ] , [ y 2 ] , … … , [ y n ] ] n × 1 y=[[y^1],[y^2],……,[y^n]]_{n×1} y=[[y1],[y2],……,[yn]]n×1,需要求一个 θ = [ [ θ 1 ] , [ θ 2 ] ] 2 × 1 θ=[[θ_1],[θ_2]]_{2×1} θ=[[θ1],[θ2]]2×1,使得以上数据可以拟合为一个函数 y ^ \hat y y^下面推导梯度下降的公式。
假设的,在多元回归或者逻辑回归的损失函数设为:
L
o
s
s
=
1
2
⋅
1
n
⋅
∑
i
=
1
n
(
y
^
i
−
y
i
)
2
=
1
2
⋅
1
n
⋅
[
(
x
1
1
θ
1
+
x
2
1
θ
2
−
y
1
)
2
+
(
x
1
2
θ
1
+
x
2
2
θ
2
−
y
2
)
2
+
…
…
+
(
x
1
n
θ
1
+
x
2
n
θ
2
−
y
n
)
2
]
则
∂
L
o
s
s
∂
θ
1
=
1
n
⋅
[
x
1
1
⋅
(
x
1
1
θ
1
+
x
2
1
θ
2
−
y
1
)
+
x
1
2
⋅
(
x
1
2
θ
1
+
x
2
2
θ
2
−
y
2
)
+
…
…
+
x
1
n
⋅
(
x
1
n
θ
1
+
x
2
n
θ
2
−
y
n
)
]
=
1
n
⋅
∑
i
=
1
n
x
1
i
(
x
1
i
θ
1
+
x
2
i
θ
2
−
y
i
)
=
1
n
⋅
∑
i
=
1
n
x
1
i
(
y
^
i
−
y
i
)
同理可得,
∂
L
o
s
s
∂
θ
2
=
1
n
⋅
∑
i
=
1
n
x
2
i
(
y
^
i
−
y
i
)
\frac{\partial Loss}{\partial \theta _2} =\frac{1}{n}·\sum_{i=1}^{n}x_2^i(\hat y^i-y^i)
∂θ2∂Loss=n1⋅i=1∑nx2i(y^i−yi)
所以
∂
L
o
s
s
∂
θ
j
=
1
n
⋅
∑
i
=
1
n
x
j
i
(
y
^
i
−
y
i
)
\frac{\partial Loss}{\partial \theta _j} =\frac{1}{n}·\sum_{i=1}^{n}x_j^i(\hat y^i-y^i)
∂θj∂Loss=n1⋅i=1∑nxji(y^i−yi)
则得到梯度更新的公式为
θ
j
′
=
θ
j
+
α
⋅
1
n
⋅
∑
i
=
1
n
x
j
i
(
y
^
i
−
y
i
)
\theta_j^{'} =\theta_j+\alpha· \frac{1}{n}·\sum_{i=1}^{n}x_j^i(\hat y^i-y^i)
θj′=θj+α⋅n1⋅i=1∑nxji(y^i−yi)
每一次参数更新时,按照所有样本来计算梯度,也就是所有样本都参与到Loss值的计算中。
批量梯度下降对于凸优化问题可以找到全局的最优解,这种方法在样本量不大的情况下可以快速收敛,但是如果样本的量过大,每次参数更新都需要全部的样本的参与,单次更新的时间长,需要的存储空间也大。其更新公式如下:
θ
j
′
=
θ
j
+
α
⋅
1
n
⋅
∑
i
=
1
n
x
j
i
(
y
^
i
−
y
i
)
for every j
\theta_j^{'} =\theta_j+\alpha· \frac{1}{n}·\sum_{i=1}^{n}x_j^i(\hat y^i-y^i) \quad \text{for every j}
θj′=θj+α⋅n1⋅i=1∑nxji(y^i−yi)for every j
每一次参数更新只需要采用一个样本来计算梯度
随机梯度下降不能保证每一次的更新都按照全局最优点出发,随机梯度下降相对于批量梯度下降的单次更新时间快,存储要求小,在非凸优化问题上,这种方法通常可以更快的收敛到一个局部最优解。其更新公式如下:
for i to n:
θ
j
′
=
θ
j
+
α
⋅
(
y
^
i
−
y
i
)
for every j
每一次参数的更新,只需要选取一个小批量(mini-batch) b 的样本进行计算
小批量随机梯度下降是BGD和SGD的中间方案,继承了两者的优点。其更新公式如下:
for i to n:
θ
j
′
=
θ
j
+
α
⋅
1
b
⋅
∑
i
i
+
b
−
1
x
j
i
(
y
^
i
−
y
i
)
for every j
数据准备
import numpy as np
x0=np.random.randint(1,2,100).reshape(100,1)
x1=np.random.randint(1,10,100).reshape(100,1)
y=x0+x1
X=np.hstack((x0,x1))
print(X.shape[0])
# print(X)# X是100*2
# print(y)# y是100*1
批量梯度下降
# 批量梯度下降BGD def BGD(X,y): ept=0.001# 精度 loss=1 alpha=0.01# 学习率 max_iter=0# 梯度更新次数 theta=np.random.randint(1,10,(X.shape[1],1))# 初始化theta # print(theta) # 2*1 # 收敛的条件 while max_iter<10000 and loss>ept: # 损失函数关于theta的偏导数 partial=(1/X.shape[0])*X.T.dot(X.dot(theta)-y) # partial=X.T.dot(X.dot(theta)-y)# 2*1 # 梯度更新 theta=theta-alpha*partial # print('%s:partial:%s,theta:%s'%(max_iter,partial,theta)) max_iter+=1 loss=(1/(2*X.shape[0]))*np.sum((X.dot(theta)-y)**2) # loss=(1/2)*np.sum((X.dot(theta)-y)**2) # print("loss:",loss) return max_iter,theta max_iter,theta=BGD(X,y) print('BGD:max_iter:%s\n theta:%s'%(max_iter,theta))
随机梯度下降
# 随机梯度下降SGD def SGD(X,y): ept=0.001# 精度 loss=1 alpha=0.01# 学习率 max_iter=0# 梯度更新次数 theta=np.random.randint(1,10,(X.shape[1],1))# 初始化theta # print(theta) # 2*1 numSample=X.shape[0] while max_iter<10000 and loss>ept: # 随机抽取一个样本 i=np.random.randint(0,numSample) # 损失函数对theta的偏导数,这个偏导数是单个的 partial=X[i:i+1,:].T.dot((X[i:i+1,:].dot(theta)-y[i,:]).reshape(1,1)) theta=theta-alpha*partial max_iter+=1 loss=(1/(2*X.shape[0]))*np.sum((X.dot(theta)-y)**2) # loss=(1/2)*np.sum((X.dot(theta)-y)**2)# 损失函数和上面的一样 return max_iter,theta max_iter,theta=SGD(X,y) print('SGD:max_iter:%s\n theta:%s'%(max_iter,theta))
# 随机梯度下降SGD def SGD(X,y): ept=0.001# 精度 loss=1 alpha=0.01# 学习率 max_iter=0# 梯度更新次数 theta=np.random.randint(1,10,(X.shape[1],1))# 初始化theta # print(theta) # 2*1 numSample=X.shape[0] while max_iter<10000 and loss>ept: for i in range(numSample): # 随机抽取一个样本 # i=np.random.randint(0,numSample) # 损失函数对theta的偏导数,这个偏导数是单个的 partial=X[i:i+1,:].T.dot((X[i:i+1,:].dot(theta)-y[i,:]).reshape(1,1)) theta=theta-alpha*partial max_iter+=1 loss=(1/(2*X.shape[0]))*np.sum((X.dot(theta)-y)**2) # loss=(1/2)*np.sum((X.dot(theta)-y)**2)# 损失函数和上面的一样 return max_iter,theta max_iter,theta=SGD(X,y) print('SGD:max_iter:%s\n theta:%s'%(max_iter,theta))
ps:这里为什么给出两种代码,其实这里按照我给出的公式其实第二种代码才是对应的代码,第二种的max_iter其实可以认为是epoch,表示周期,因为一个周期需要所有的样本数据都参与一次。而第一种代码的max_iter表示的是参数更新的次数,这两个是不同的。在批量梯度下降中,参数更新的次数与周期在数目上是一致的,这是因为批量梯度下降每一次参数更新需要所有的样本参与。同理下面的小批量随机梯度下降也是有两种代码的。
# 小批量随机梯度下降,这里的小批量是两个样本 def MBGD(X,y): ept=0.001# 精度 loss=1 alpha=0.01# 学习率 max_iter=0# 梯度更新次数 theta=np.random.randint(1,10,(X.shape[1],1))# 初始化theta # print(theta) # 2*1 numSample=X.shape[0] while max_iter<10000 and loss>ept: # 随机选择一个批量的数据 i=np.random.randint(0,numSample-1) # 损失函数对theta的偏导数 partial=(1/2)*X[i:i+2,:].T.dot(X[i:i+2,:].dot(theta)-y[i:i+2,:]) # partial=X[i:i+2,:].T.dot(X[i:i+2,:].dot(theta)-y[i:i+2,:]) theta=theta-alpha*partial max_iter+=1 loss=(1/(2*X.shape[0]))*np.sum((X.dot(theta)-y)**2) # loss=(1/2)*np.sum((X.dot(theta)-y)**2)# 损失函数和上面的一样 return max_iter,theta max_iter,theta=MBGD(X,y) print('MBGD:max_iter:%s\n theta:%s'%(max_iter,theta))
# 小批量随机梯度下降,这里的小批量是两个样本 def MBGD(X,y): ept=0.001# 精度 loss=1 alpha=0.01# 学习率 max_iter=0# 梯度更新次数 theta=np.random.randint(1,10,(X.shape[1],1))# 初始化theta # print(theta) # 2*1 numSample=X.shape[0] mini_batch=2 while max_iter<10000 and loss>ept: for i in range(0,numSample-2,mini_batch): # 随机选择一个批量的数据 # i=np.random.randint(0,numSample-1) # 损失函数对theta的偏导数 partial=(1/mini_batch)*X[i:i+mini_batch,:].T.dot(X[i:i+mini_batch,:].dot(theta)-y[i:i+mini_batch,:]) # partial=X[i:i+2,:].T.dot(X[i:i+2,:].dot(theta)-y[i:i+2,:]) theta=theta-alpha*partial max_iter+=1 loss=(1/(2*X.shape[0]))*np.sum((X.dot(theta)-y)**2) # loss=(1/2)*np.sum((X.dot(theta)-y)**2)# 损失函数和上面的一样 return max_iter,theta max_iter,theta=MBGD(X,y) print('MBGD:max_iter:%s\n theta:%s'%(max_iter,theta)) # https://blog.csdn.net/eevee_1/article/details/134944669
以上,仅个人理解,欢迎批评指正。
参考文章:批梯度下降(BGD)、随机梯度下降(SGD)、小批量梯度下降(MBGD)的理解和python 实现
pytorch(二)梯度下降算法
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。