【刘二大人】PyTorch深度学习实践
文章目录
- 一、overview
- 1 机器学习
- 二、Linear_Model(线性模型)
- 1 例子引入
- 三、Gradient_Descent(梯度下降法)
- 1 梯度下降
- 2 梯度下降与随机梯度下降(SGD)对比
- 3 Mini-Batch
- 四、Back Propagation(反向传播)
- 1 线性模型叠加的神经网络
- 2 反向传播
- 3 在PyTorch中进行前馈和反馈的运算
- 五、PyTorch实现线性回归
- 1、准备数据集
- 2、设计模型
- 3、构造损失函数和优化器
- 4、训练过程
- 5、代码实现
- 六、Logistics_Regression(逻辑回归)
- 1 二分类和sigmoid函数
- 2 逻辑回归
- 3 代码实现
- 七、Multiple Dimension Input(多维特征的输入)
- 1 多维逻辑回归模型
- 2 线性层和人工神经网络
- 3 例子:糖尿病是否恶化的预测
- 3.1 数据集
- 3.2 代码实现
- 八、Dataset(加载数据集) and Dataloader(Mini-batch)
- 1 Dataloader
- 2 定义Dataset
- 3 代码实现
- 九、softmax classifier
- 1 softmax层
- 2 损失函数
- 3 代码实现
- 十、CNN
- 1 basic_CNN
- 1.1 卷积神经网络
- 1.2 卷积操作
- 1.2.1 单通道输入卷积操作
- 1.2.2 3通道输入卷积操作
- 1.2.3 N通道输入 M通道输出卷积操作**
- 1.2.4 卷积层
- 1.3 basic代码实现
- 1.4 扩充(padding)
- 1.5 步长(stride)
- 1.6 池化(polling)
- 1.7 如何把运算迁移至GPU
- 1.7.1 代码实现
- 2 advanced_CNN ---- GoogLeNet
- 2.1 GoogLeNet
- 2.2 Inception Module
- 2.2.1 1*1卷积
- 2.2.2 拼接
- 2.2.3 Inception Module代码
- 2.3 GoogLeNet代码实现
- 3 advanced_CNN ---- ResNet
- 3.1 ResNet
- 3.1.1 Residual Block(残差结构块)
- 3.1.2 代码实现
- 十一、RNN
- 1 basic_RNN
- 2 在pytorch中实现RNN
- 2.1 定义RNNCell
- 2.1.1 代码实现
- 2.2 使用RNN模型
- 2.2.1 numlayers
- 2.2.2 batch_first
- 2.2.2 代码实现
- 3 hello->ohlol
- 3.1 代码实现
一、overview
1 机器学习
想写一点,但是不知道写啥,需要补充
机器学习(大多数基于统计)就是用算法代替大脑进行运算
合适的算法需要不断调整:设置模型->利用数据集训练->验证
prediction:将视觉接受的信息转化为抽象概念
机器学习与人工智能的关系
二、Linear_Model(线性模型)
DataSet(数据集) -> Model(模型) -> Training(训练) -> inferring(推理)
关于数据集的介绍:训练集 测试集 验证集
1 例子引入
已知数据集学习时间x[1,2,3] 成绩y[2,4,6],测试数据集x=4,y=?
此时数据集分为训练数据集和测试数据集
一般情况下为了避免过拟合,会将测试数据集的一部分作为开发(验证)数据集,用来验证模型的准确程度
监督学习:有标签的数据学习,根据输入值和输出值对模型进行调整;利用一组已知类别的样本调整分类器的参数,使其达到所要求性能的过程
线性模型
获取最优的线性模型:因为此时数据集较少采用简单的线性模型。随机选取w以后,计算损失值,然后不停调整w的值(在某个范围内穷举)使得损失值最小
Training Loss针对一个样本
Mean Square Error(MSE平均平方误差)针对整个训练集
代码实现
损失曲线
三、Gradient_Descent(梯度下降法)
梯度下降法
利用了贪心的思想,查找当前下降最快的位置
梯度下降法的基本思想可以类比为一个下山的过程。
假设这样一个场景:一个人被困在山上,要想快速下山就要寻找最陡峭的地方。首先以他当前的所处的位置为基准,寻找这个位置最陡峭的地方,然后朝着下降方向走一步,然后又继续以当前位置为基准,再找最陡峭的地方,再走直到最后到达最低处;同理上山也是如此,只是这时候就变成梯度上升算法了
梯度下降的基本过程就和下山的场景很类似。
首先,我们有一个可微分的函数。这个函数就代表着一座山。我们的目标就是找到这个函数的最小值,也就是山底。根据之前的场景假设,最快的下山的方式就是找到当前位置最陡峭的方向,然后沿着此方向向下走,对应到函数中,就是找到给定点的梯度 ,然后朝着梯度相反的方向,就能让函数值下降的最快!因为梯度的方向就是函数之变化最快的方向(在后面会详细解释)
所以,我们重复利用这个方法,反复求取梯度,最后就能到达局部的最小值,这就类似于我们下山的过程。而求取梯度就确定了最陡峭的方向,也就是场景中测量方向的手段。那么为什么梯度的方向就是最陡峭的方向呢?
在单变量的函数中,梯度其实就是函数的微分,代表着函数在某个给定点的切线的斜率
在多变量函数中,梯度是一个向量,向量有方向,梯度的方向就指出了函数在给定点的上升最快的方向
到达山底,就需要在每一步观测到此时最陡峭的地方,梯度就恰巧告诉了我们这个方向。梯度的方向是函数在给定点上升最快的方向,那么梯度的反方向就是函数在给定点下降最快的方向,所以我们只要沿着梯度的方向一直走,就能走到局部的最低点!
1 梯度下降
在线性模型中采用了穷举法,但是对于数据集较大的时候穷举不可行,因此提出梯度下降进行优化。
随机选取一个点,计算梯度,并朝着函数值下降最快的方向走,并且更新w值
公式推导
代码实现及曲线
若没有趋近于一个数值说明训练失败,可以适当调整学习率(α)的值
2 梯度下降与随机梯度下降(SGD)对比
梯度下降法遇到鞍点无法跳出,但是随机梯度下降可能会跳跃鞍点
SGD算法是从样本中随机抽出一组,训练后按梯度更新一次,然后再抽取一组,再更新一次,在样本量及其大的情况下,可能不用训练完所有的样本就可以获得一个损失值在可接受范围之内的模型了。
这里的随机是指每次迭代过程中,样本都要被随机打乱,打乱是有效减小样本之间造成的参数更新抵消问题。
SGD代码实现
对梯度下降和随机梯度下降综合一下获取更好的性能
对数据进行分组mini-batch
:组内梯度下降,组间随机梯度下降
3 Mini-Batch
**full batch:**在梯度下降中需要对所有样本进行处理过后然后走一步,如果样本规模的特别大的话效率就会比较低。假如有500万,甚至5000万个样本(业务场景中,一般有几千万行,有些大数据有10亿行)的话走一轮迭代就会非常的耗时。
为了提高效率,我们可以把样本分成等量的子集。 例如我们把100万样本分成1000份, 每份1000个样本, 这些子集就称为mini batch。mini-batch的大小一般取2
的n次方
然后我们分别用一个for循环遍历这1000个子集。 针对每一个子集做一次梯度下降。 然后更新参数w和b的值。接着到下一个子集中继续进行梯度下降。 这样在遍历完所有的mini batch之后我们相当于在梯度下降中做了1000次迭代。 我们将遍历一次所有样本的行为叫做一个 epoch,也就是一个世代。 在mini batch下的梯度下降中做的事情其实跟full batch一样,只不过我们训练的数据不再是所有的样本,而是一个个的子集。 这样在mini batch我们在一个epoch中就能进行1000次的梯度下降,而在full batch中只有一次。 这样就大大的提高了我们算法的运行速度。
四、Back Propagation(反向传播)
可以在图上进行梯度传播帮助我们建立一个更好的模型结构
1 线性模型叠加的神经网络
如图所示线性模型可以看做一个简单的神经网络
由线性模型组成的简单神经网络
可以发现这个神经网络进行的运算无论叠加多少层一直都是线性运算,提高层数没有意义
因此为了提高模型的复杂程度,我们为神经网络添加一个非线性因素,例如sigmoid函数
在进行完加法运算以后对这个中间变量进行非线性的变换
复杂的神经网络一般需要多层连接,其中主要是升维或降维的操作
2 反向传播
进行反向传播前先回顾一下链式求导法则:链式求导
反向传播的链式求导:
1.创建计算图进行前馈运算,沿箭头方向进行运算
2.求z,同时算出z关于w,z关于x的偏导
3.求最终的输出L,并得到最终的损失值关于输出z的偏导(前馈的过程就是一步一步算到loss,而loss再一步一步反向传播,就可以拿到上一层L对z的偏导)4.利用链式法则反向求偏导(损失关于w和x的偏导)
简单线性模型的完整计算图(包括前馈与反馈)
3 在PyTorch中进行前馈和反馈的运算
先了解一下Tensor:Tensor
代码实现:
import torchx_data = [1.0,2.0,3.0]
y_data = [2.0,4.0,6.0]w = torch.tensor([1.0]) # w 是tensor类型
w.requires_grad = True # 为true表示需要计算梯度def forward(x):return x * w # 此时w为tensor类型,会自动将x也转换成tensor类型def loss(x,y): # 失败函数 构建计算图直接用张量y_pred = forward(x)return (y_pred - y) ** 2print("predict (before training",4,forward(4).item())for epoch in range(100):for x,y in zip(x_data,y_data):l = loss(x,y) # 前馈,计算lossl.backward() # 反馈,l是张量,调用backward函数,可以把数据链路上所有需要梯度的地方都求出来并存到w.grad里# 每进行一次反馈重新构造一个计算图print('\tgrad:',x,y,w.grad.item()) # item 直接把数值拿出来做成标量w.data = w.data - 0.01 * w.grad.data # 此时的w.grad还是一个张量,需要取到data值进行计算,这样不会建立计算图w.grad.data.zero_() # 梯度数据清零print("progress:",epoch,l.item())print("predict (after training)",4,forward(4).item())
五、PyTorch实现线性回归
1、准备数据集
import torch
x_data = torch.Tensor([[1.0],[2.0],[3.0]])
y_data = torch.Tensor([[2.0],[4.0],[6.0]])
2、设计模型
3、构造损失函数和优化器
4、训练过程
5、代码实现
import torch
x_data = torch.Tensor([[1.0],[2.0],[3.0]])
y_data = torch.Tensor([[2.0],[4.0],[6.0]])# 线性回归模型
class LinearModel(torch.nn.Module): # 从module继承类def __init__(self):# super调用父类构造super(LinearModel,self).__init__()self.linear = torch.nn.Linear(1,1) # (1,1)输入1维,输出也是1维def forward(self,x): #只能写forwardy_pred = self.linear(x) # 实现一个可调用的对象return y_predmodel = LinearModel() # callablecriterion = torch.nn.MSELoss(reduction='sum') # MSEloss继承自nn.module
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)for epoch in range(1000): # 迭代100次y_pred = model(x_data)loss = criterion(y_pred,y_data) # 前馈print(epoch,loss.item()) #此处要用loss.item() #loss是个对象,调用时会自动调用__str__()函数,不会产生计算图optimizer.zero_grad() # 梯度归零loss.backward() # 反向传播optimizer.step() # 更新print('w=',model.linear.weight.item())
print('b=',model.linear.bias.item())x_test = torch.Tensor([[4.0]])
y_test = model(x_test)
print('y_pred=',y_test.data)
六、Logistics_Regression(逻辑回归)
逻辑回归和线性回归
“分类”和“回归”
逻辑回归和线性回归异同
逻辑回归中因变量是离散的,而线性回归中因变量是连续的这是两者最大的区别。因此分类问题中最好使用逻辑回归。
逻辑回归本质是线性回归,但是它加了sigmoid函数
1 二分类和sigmoid函数
二分类损失函数
利用交叉熵函数计算概率,计算的是分布的差异
KL散度
交叉熵
Mini-Batch
2 逻辑回归
【BCE/MSE/CE】
由于逻辑回归本质也是线性回归,所以利用pytorch解决逻辑回归时参考线性回归的四步。
- 准备数据集
- 设计模型
- 构造损失函数和优化器
- 训练周期
3 代码实现
import numpy as np
import torch
import matplotlib.pyplot as plt
import torch.nn.functional as F #包含了许多函数,sigmoid tanh relux_data = torch.Tensor([[1.0],[2.0],[3.0]])
y_data = torch.Tensor([[0],[0],[1]]) #表示分类,0和1两类
#-----------------------#数据集准备class LogisticRegressionModel(torch.nn.Module):def __init__(self):super(LogisticRegressionModel,self).__init__()self.linear = torch.nn.Linear(1,1) # linear做线性变换,求wx+bdef forward(self,x):y_pred = F.sigmoid(self.linear(x)) #sigmoid函数无参,构造函数里不需要初始化,直接用就可以return y_predmodel = LogisticRegressionModel()
#-----------------------------------#创建模型criterion = torch.nn.BCELoss(reduction='sum')
# 损失函数有所不同,BCE是二分类交叉熵,MSE是均方误差
# loss是否乘1/N,影响学习率的取值
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
#-----------------------------------#构造损失函数和优化器loss_list = []
epoch_list = []for epoch in range(1000):y_pred = model(x_data)loss = criterion(y_pred,y_data)print(epoch,loss.item())optimizer.zero_grad()loss.backward()optimizer.step()
#---------------------------------------#训练周期x = np.linspace(0,10,200) # 0-10小时,200个数据点
x_t = torch.Tensor(x).view((200,1)) #200行一列的矩阵
y_t = model(x_t)
y = y_t.data.numpy()
plt.plot(x,y)
plt.plot([0,10],[0.5,0.5],c = 'r')
plt.xlabel('Hours')
plt.ylabel('Probability of Pass')
plt.grid()
plt.show()
七、Multiple Dimension Input(多维特征的输入)
1 多维逻辑回归模型
Mini-batch
2 线性层和人工神经网络
逻辑回归只有一层,多个类似逻辑回归的变换首尾相连就可以创建神经网络
矩阵是空间变换的函数,所以可以改变维度
神经网络是寻找一种非线性的空间变换的函数
linear可以做到空间维度的变换
3 例子:糖尿病是否恶化的预测
3.1 数据集
每个样本有好几个特征
四步走:
- 准备数据集
- 设计模型
- 构造损失函数和优化器
- 训练周期
3.2 代码实现
import numpy as np
import torch
import matplotlib.pyplot as pltxy = np.loadtxt('D:\桌面文件\深度学习\刘二大人\PyTorch深度学习实践\diabetes.csv.gz',delimiter=',',dtype = np.float32) #32位浮点数
x_data = torch.from_numpy(xy[:,:-1]) # 最后一列不要
y_data = torch.from_numpy(xy[:,[-1]]) # 只要最后一列 []保证得到矩阵
#-------------------------#准备数据集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)self.linear3 = torch.nn.Linear(4,1)# 添加非线性的变化,此处是nn下的sigmoid,是一个模块# 把此处sigmoid作为一个运算模块,继承自module,不需要传参,只构建一个# 与functional下的没有区别self.sigmoid = torch.nn.Sigmoid()self.activate = torch.nn.ReLU()def forward(self,x):# x = self.sigmoid(self.linear1(x))# x = self.sigmoid(self.linear2(x))# x = self.sigmoid(self.linear3(x))x = self.activate(self.linear1(x))x = self.activate(self.linear2(x))x = self.sigmoid(self.linear3(x))return xmodel = Model()
#----------------------------------------#创建模型criterion = torch.nn.BCELoss(reduction='sum')
# 损失函数有所不同,BCE是二分类交叉熵,MSE是均方误差
# loss是否乘1/N,影响学习率的取值
optimizer = torch.optim.SGD(model.parameters(),lr=0.01)
#-----------------------------------#构造损失函数和优化器epoch_x = []
loss_y = []
for epoch in range(100):#前馈y_pred = model(x_data) # 所有数据loss = criterion(y_pred,y_data)print(epoch,loss.item())#画epoch-loss图,x和y轴的数据epoch_x.extend(epoch)loss_y.extend(loss.item())#反馈optimizer.zero_grad()loss.backward()#更新optimizer.step()
#---------------------------------------#训练周期
# 画图
plt.plot(epoch_x, loss_y)
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()
八、Dataset(加载数据集) and Dataloader(Mini-batch)
epoch、Batch-Size、Iteration
1 Dataloader
2 定义Dataset
num_workers注意点
Windows和linux多进程的库不一样,Windows下需要封装起来
3 代码实现
import numpy as np
import torch
import matplotlib.pyplot as plt# Dataset是抽象类,不能实例化,只能继承dataset类以后才能实例化
from torch.utils.data import Dataset
from torch.utils.data import DataLoader# 1.创建数据集
class DiabetesDataset(Dataset):def __init__(self, filepath):xy = np.loadtxt(filepath, delimiter=',', dtype=np.float32)# xy是n行9列,shape得到的[N,9]元组,shape[0]得到的是Nself.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.lendataset = DiabetesDataset('D:\桌面文件\深度学习\刘二大人\PyTorch深度学习实践\diabetes.csv.gz')
# DataLoader构造加载器
train_loader = DataLoader(dataset=dataset,batch_size=32,shuffle=True,num_workers=2)# 2.创建模型
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, 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 xmodel = Model()# 3.构造损失函数和优化器
criterion = torch.nn.BCELoss(size_average=True)
optimizer = torch.optim.SGD(model.parameters(), lr=0.1)# 4.训练周期
if __name__ == '__main__':# 外层循环for epoch in range(200):# train_loader得到的(x,y)元组放入data,从0开始for i, data in enumerate(train_loader, 0):# data_x,data_yinputs, labels = data# 前馈y_hat = model(inputs)loss = criterion(y_hat, labels)print(epoch, i, loss.item())# 反向传播optimizer.zero_grad()loss.backward()# 更新权重optimizer.step()
九、softmax classifier
将多分类的每个输出看成一个二分类用sigmoid解决的话,会导致输出概率相近
因此引入softmax,softmax对概率归一化,使得输出大于0,概率和为1,可以解决抑制问题
1 softmax层
2 损失函数
3 代码实现
import torch
import matplotlib.pyplot as plt
from torchvision import transforms # 针对图像处理
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F #使用ReLU
import torch.optim as optim # 优化器
# 1.数据集准备
batch_size = 64
# transform pytorch读图像时,神经网络希望输入比较小,
# pillow把图像转化为图像张量,单通道转化为多通道
transform = transforms.Compose([ #compose可以把[]里的数据进行pipline处理transforms.ToTensor(), # 转化成张量transforms.Normalize((0.1307,), (0.3081,)) # normalize归一化,(均值,标准差)
])
# transform放到数据集里是为了对第i个数据集直接操作
train_dataset = datasets.MNIST(root='../dataset/mnist',train=True,download=True,transform=transform)train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)test_dataset = datasets.MNIST(root='../dataset/mnist/',train=False,download=True,transform=transform)test_loader = DataLoader(test_dataset,shuffle=False,batch_size=batch_size)# 2.构造模型
class Net(torch.nn.Module):def __init__(self):super(Net, self).__init__()self.l1 = torch.nn.Linear(784, 512) self.l2 = torch.nn.Linear(512, 256)self.l3 = torch.nn.Linear(256, 128)self.l4 = torch.nn.Linear(128, 64)self.l5 = torch.nn.Linear(64, 10)def forward(self, x):# 如果是x.view(1,-1),表示需要转化成一行的向量,但是不知道多少列,需要电脑计算x = x.view(-1, 784) # view改变张量的形式,把(N,1,28,28)变成二阶,-1表示0维度的数字不变x = F.relu(self.l1(x))x = F.relu(self.l2(x))x = F.relu(self.l3(x))x = F.relu(self.l4(x))return self.l5(x) #最后一层不激活model = Net()
# 3.损失函数和优化器
criterion = torch.nn.CrossEntropyLoss()# 交叉熵损失
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5) #用带冲量的# 4.训练周期+测试集
def train(epoch):running_loss = 0.0for batch_size, data in enumerate(train_loader, 0):inputs, target = data # x,yoptimizer.zero_grad() # 在优化器优化之前,进行权重清零;outputs = model(inputs)loss = criterion(outputs, target)loss.backward()optimizer.step()running_loss += loss.item() # 累计lossif batch_size % 300 == 299:print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_size + 1, running_loss / 300))def test():correct = 0total = 0with torch.no_grad(): # 不需要计算梯度for data in test_loader:images, labels = dataoutputs = model(images)# 求每一行最大值的下标,返回最大值,和下标_, predicted = torch.max(outputs.data, dim=1) total += labels.size(0) # batch_sizecorrect += (predicted == labels).sum().item() # 比较下标与预测值是否接近,求和表示猜对了几个print('Accuracy on test set: %d %%' % (100 * correct / total))if __name__ == '__main__':for epoch in range(100):train(epoch)test()
十、CNN
1 basic_CNN
1.1 卷积神经网络
1.2 卷积操作
**CCD相机模型:**这是一种通过光敏电阻,利用光强对电阻的阻值影响,对应地影响色彩亮度实现不同亮度等级像素采集的原件。三色图像是采用不同敏感度的光敏电阻实现的。
**矢量图像:**也就是PPT里通过圆心、边、填充信息描述而来的图像,而非采集的图像;
1.2.1 单通道输入卷积操作
1.2.2 3通道输入卷积操作
1.2.3 N通道输入 M通道输出卷积操作**
1.2.4 卷积层
1.3 basic代码实现
import torchin_channel, out_channel = 5, 10
width, height = 100, 100
kernel_size = 3 # 卷积核大小
batch_size = 1
# 正态分布采样 随机生成
input = torch.randn(batch_size, in_channel,width,height)conv_layer = torch.nn.Conv2d(in_channel, # input nout_channel, # output m kernel_size=kernel_size)output = conv_layer(input)print(input.shape)
print(output.shape)
print(conv_layer.weight.shape) #[输出通道input,输入通道output,卷积核3*3]
1.4 扩充(padding)
padding是为了让源图像最外一圈或多圈像素(取决于kernel的尺寸),能够被卷积核中心取到。
这里有个描述很重要:想要使源图像(1,1)的位置作为第一个与kernel中心重合,参与计算的像素,想想看padding需要扩充多少层,这样就很好计算了吧
1.5 步长(stride)
stride操作指的是每次kernel窗口滑动的步长,默认值是1
1.6 池化(polling)
简单卷积神经网络
1.7 如何把运算迁移至GPU
- 把模型迁移至GPU
- 用来计算的张量迁移至GPU
1.7.1 代码实现
import matplotlib.pyplot as plt
import torchfrom torchvision import datasets, transforms
from torch.utils.data import DataLoaderimport torch.nn.functional as F
import torch.optim as optim # (可有可无)import osos.environ['KMP_DUPLICATE_LIB_OK'] = 'TRUE'batch_size = 64
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))
])train_dataset = datasets.MNIST(root='../dataset/mnist/',train=True,download=True,transform=transform)
train_loader = DataLoader(dataset=train_dataset,shuffle=True,batch_size=batch_size,)test_dataset = datasets.MNIST(root='../dataset/mnist/',train=False,download=True,transform=transform)test_loader = DataLoader(dataset=test_dataset,shuffle=False,batch_size=batch_size,)class Net(torch.nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = torch.nn.Conv2d(in_channels=1, out_channels=10, kernel_size=5)self.conv2 = torch.nn.Conv2d(in_channels=10, out_channels=20, kernel_size=5)self.pooling = torch.nn.MaxPool2d(2)self.fc = torch.nn.Linear(320, 10)def forward(self, x):batch_size = x.size(0)x = F.relu(self.pooling(self.conv1(x)))x = F.relu(self.pooling(self.conv2(x)))x = x.view(batch_size, -1)x = self.fc(x)return xmodel = Net()
# 选择是GPU CPU
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
# 表示把整个模型涉及到的权重迁移到GPU
model.to(device)criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)def train(epoch):running_loss = 0.0for batch_index, (inputs, labels) in enumerate(train_loader, 0):# 迁移至GPU(模型数据要在同一块显卡上)inputs, labels = inputs.to(device), labels.to(device)y_hat = model(inputs)loss = criterion(y_hat, labels)optimizer.zero_grad()loss.backward()optimizer.step()running_loss += loss.item()if batch_size % 10 == 9:print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_index + 1, running_loss / 300))def test():correct = 0total = 0with torch.no_grad():for (images, labels) in test_loader:images, labels = images.to(device), labels.to(device)outputs = model(images)_, pred = torch.max(outputs.data, dim=1)total += labels.size(0)correct += (pred == labels).sum().item()print('accuracy on test set: %d %%' % (100 * correct / total))return correct / totalif __name__ == '__main__':epoch_list = []acc_list = []for epoch in range(10):train(epoch)acc = test()epoch_list.append(epoch)acc_list.append(acc)plt.plot(epoch_list, acc_list)plt.xlabel('epoch')plt.ylabel('accuracy')plt.show()
2 advanced_CNN ---- GoogLeNet
2.1 GoogLeNet
GoogLeNet是一种串行结构的复杂网络;想要实现复杂网络,并且较少代码冗余和多次重写相同功能的程序,面向过程的语言使用函数,面向对象的语言使用类。
在CNN当中,使用Module和block这种模块将具有复用价值的代码块封装成一块积木,供拼接使用。
其中一些重复出现的Module称为Inception
2.2 Inception Module
2.2.1 1*1卷积
表面上看是11像素大小的卷积核,它的意义不过是调整输入和输出的通道数之间的关系
但是它可以加速运算,他的作用的确是加速运算,不过其中的原理是:通过11的核处理过的图像,可以减少后续卷积层的输入通道数
加速运算
2.2.2 拼接
以通道的维度拼接
2.2.3 Inception Module代码
#根据上面将结果的内容,一部分在__init__,一部分在forward
class InceptionA(torch.nn.Module):
#初始通道未说明,为了在实例化的时候可以指明输入通道是多少def __init__(self, in_channels):# 1super(InceptionA, self).__init__()self.branch1x1 = nn.Conv2d(in_channels, 16, kernel_size=1) # 乘号用字母x代替;# 2self.branch5x5_1 = nn.Conv2d(in_channels, 16, kernel_size=1)self.branch5x5_2 = nn.Conv2d(16, 24, kernel_size=5, padding=2)# 3self.branch3x3_1 = nn.Conv2d(in_channels, 16, kernel_size=1) # 第一个卷积核都是1x1,这个东西是减少操作数的,为了加速运算self.branch3x3_2 = nn.Conv2d(16, 24, kernel_size=3, padding=1)self.branch3x3_3 = nn.Conv2d(24, 24, kernel_size=3, padding=1)# 4self.branch_pool = nn.Conv2d(in_channels, 24,kernel_size=1) # branch 这个词儿,在S2D引用的laina的代码里见过,一个是upper——branch,一个是bottom——branch;def forward(self, x):# 1branch1x1 = self.branch1x1(x)# 2branch5x5 = self.branch5x5_1(x)branch5x5 = self.branch5x5_2(branch5x5)# 3branch3x3 = self.branch3x3_1(x)branch3x3 = self.branch3x3_2(branch3x3)branch3x3 = self.branch3x3_3(branch3x3)# 4branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)branch_pool = self.branch_pool(branch_pool)# cat拼接output = [branch1x1, branch5x5, branch3x3, branch_pool]return torch.cat(output, dim=1)
2.3 GoogLeNet代码实现
# advanced CNNimport torch
from torch import nn, optim
import torch.nn.functional as F
from torchvision import datasets # dataset 引用位置
from torch.utils.data import DataLoader # DataLoader 引用位置
from torchvision import transformsbatch_size = 64
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081,))])train_dataset = datasets.MNIST(root='../dataset/mnist', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)test_dataset = datasets.MNIST(root='../dataset/mnist/', train=False, download=True, transform=transform)
test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size)class InceptionA(torch.nn.Module):def __init__(self, in_channels):# 1super(InceptionA, self).__init__()self.branch1x1 = nn.Conv2d(in_channels, 16, kernel_size=1) # 乘号用字母x代替;# 2self.branch5x5_1 = nn.Conv2d(in_channels, 16, kernel_size=1)self.branch5x5_2 = nn.Conv2d(16, 24, kernel_size=5, padding=2)# 3self.branch3x3_1 = nn.Conv2d(in_channels, 16, kernel_size=1) # 第一个卷积核都是1x1,这个东西是减少操作数的,为了加速运算self.branch3x3_2 = nn.Conv2d(16, 24, kernel_size=3, padding=1)self.branch3x3_3 = nn.Conv2d(24, 24, kernel_size=3, padding=1)# 4self.branch_pool = nn.Conv2d(in_channels, 24,kernel_size=1) # branch 这个词儿,在S2D引用的laina的代码里见过,一个是upper——branch,一个是bottom——branch;def forward(self, x):# 1branch1x1 = self.branch1x1(x)# 2branch5x5 = self.branch5x5_1(x)branch5x5 = self.branch5x5_2(branch5x5)# 3branch3x3 = self.branch3x3_1(x)branch3x3 = self.branch3x3_2(branch3x3)branch3x3 = self.branch3x3_3(branch3x3)# 4branch_pool = F.avg_pool2d(x, kernel_size=3, stride=1, padding=1)branch_pool = self.branch_pool(branch_pool)# cat拼接output = [branch1x1, branch5x5, branch3x3, branch_pool]return torch.cat(output, dim=1)class Net(nn.Module):def __init__(self):super(Net, self).__init__()# 构造两个卷积层,10,88self.conv1 = nn.Conv2d(1, 10, kernel_size=5)self.conv2 = nn.Conv2d(88, 20, kernel_size=5)# 输入通道不同的两个Inceptionself.incep1 = InceptionA(in_channels=10)self.incep2 = InceptionA(in_channels=20)self.mp = nn.MaxPool2d(2)self.fc = nn.Linear(1408, 10) # 可以先不写,通过报错查看答案填写数字def forward(self, x):in_size = x.size(0)#卷积-池化-ReLUx = F.relu(self.mp(self.conv1(x))) # 输入10个通道x = self.incep1(x) # 输出88x = F.relu(self.mp(self.conv2(x))) # 输入20x = self.incep2(x) x = x.view(in_size, -1) # 1408x = self.fc(x)return xmodel = Net()criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)def train(epoch):running_loss = 0.0for batch_idx, data in enumerate(train_loader, 0):inputs, target = dataoptimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, target)loss.backward()optimizer.step()running_loss += loss.item()if batch_idx % 300 == 299:print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))running_loss = 0.0def test():correct = 0total = 0with torch.no_grad():for data in test_loader:images, labels = dataoutputs = model(images)_, predicted = torch.max(outputs.data, dim=1)total += labels.size(0)correct += (predicted == labels).sum().item()print('accuracy on test set: %d %% ' % (100 * correct / total))if __name__ == '__main__':for epoch in range(10):train(epoch)test()
3 advanced_CNN ---- ResNet
层数越多不一定训练效果越好,有过拟合和梯度消失问题,提出了ResNet
3.1 ResNet
以往的网络模型是这种Plain Net形式:输入数据x,经过Weight Layer(可以是卷积层,也可以是池化或者线性层),再通过激活函数加入非线性影响因素,最后输出结果H(x);这种方式使得H(x)对x的偏导数的值分布在(0,1)之间,这在反向传播、复合函数的偏导数逐步累乘的过程中,必然会导致损失函数L对x的偏导数的值,趋近于0,而且,网络层数越深,这种现象就会越明显,最终导致最开始的(也就是靠近输入的)层没有获得有效的权重更新,甚至模型失效;
ResNet采用了一个非常巧妙的方式解决了H(x)对x的偏导数的值分布在(0,1)之间这个问题:在以往的框架中,加入一个跳跃,再原有的网络输出F(x)的基础上,将输入x累加到上面,这样一来,在最终输出H(x)对输入数据x求偏导数的时候,这个结果就会分布在(1,2)之间,这样就不怕网络在更新权重梯度累乘的过程中,出现乘积越来越趋于0而导致的梯度消失问题;
3.1.1 Residual Block(残差结构块)
3.1.2 代码实现
import torch
from torch import nn, optim
from torchvision import datasets
from torch.utils.data import DataLoader
from torchvision import transforms
import torch.nn.functional as F
import matplotlib.pyplot as pltbatch_size = 64
transforms = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307,), (0.3081))])train_dataset = datasets.MNIST(root='../dataset/mnist/', train=True, download=True, transform=transforms)
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)test_dataset = datasets.MNIST(root='../dataset/mnist', train=True, download=True, transform=transforms)
test_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size)class ResidualBlock(nn.Module):def __init__(self, channels):super(ResidualBlock, self).__init__()self.channels = channelsself.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)def forward(self, x):y = F.relu(self.conv1(x))y = self.conv2(y)return F.relu(x + y)class Net(nn.Module):def __init__(self):super(Net, self).__init__()self.conv1 = nn.Conv2d(1, 16, kernel_size=5)self.conv2 = nn.Conv2d(16, 32, kernel_size=5)self.mp = nn.MaxPool2d(2)# 两个残差结构块self.rbloch1 = ResidualBlock(16)self.rbloch2 = ResidualBlock(32)self.fc = nn.Linear(512, 10)def forward(self, x):# 可以逐步的测试,先输出第一个,再输出前两个,判断输出是否正确in_size = x.size(0)# 按照图片的顺行关系依次计算x = self.mp(F.relu(self.conv1(x)))x = self.rbloch1(x) # 使用残差结构块x = self.mp(F.relu(self.conv2(x)))x = self.rbloch2(x)x = x.view(in_size, -1)x = self.fc(x)return xmodel = Net()criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.5)def train(epoch):running_loss = 0.0for batch_idx, data in enumerate(train_loader, 0):inputs, target = dataoptimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, target)loss.backward()optimizer.step()running_loss += loss.item()if batch_idx % 300 == 299:print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_size + 1, running_loss / 300))running_loss = 0.0def test():correct = 0total = 0with torch.no_grad():for data in test_loader:images, labels = dataoutputs = model(images)_, predicted = torch.max(outputs.data, dim=1)total += labels.size(0)correct += (predicted == labels).sum().item()print('accuracy on test set: %d %% ' % (100 * correct / total))return correct / totalif __name__ == '__main__':epoch_list = []acc_list = []for epoch in range(10):train(epoch)acc = test()epoch_list.append(epoch)acc_list.append(acc)plt.plot(epoch_list, acc_list)
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()
十一、RNN
1 basic_RNN
对于一个全连接网络,即全部由线性层组成的网络,也称作dense(稠密型) 或者deep(深度型)网络
对于一个卷积神经网络,卷积核对多层图像处理,卷积核不变,所以权重数量少,而全连接网络的线性模型,权重数多,计算量大。
对于输入的特征具有明显的序列关系,如天气时间序列预测,就适合使用RNN循环神经网络
注意信息融合和线性层共享
2 在pytorch中实现RNN
2.1 定义RNNCell
怎样使用RNNCell
2.1.1 代码实现
import torch
# 参数设置
batch_size = 1
seq_len = 3
input_size = 4
hidden_size = 2cell = torch.nn.RNNCell(input_size = input_size,hidden_size=hidden_size)#(seq,batch,features)
dataset = torch.randn(seq_len,batch_size,input_size)
hidden = torch.zeros(batch_size,hidden_size)for idx,input in enumerate(dataset):print('='*20,idx,'='*20)print('Input size',input.shape)hidden = cell(input,hidden)print('output size',hidden.shape)print(hidden)
2.2 使用RNN模型
数据维度
2.2.1 numlayers
2.2.2 batch_first
2.2.2 代码实现
import torch
# 参数设置
batch_size = 1
seq_len = 3
input_size = 4
hidden_size = 2
#比rnncell多一个numlayers
num_layers = 1cell = torch.nn.RNN(input_size = input_size,hidden_size=hidden_size,num_layers = num_layers)#(seq,batch,features)
# 指明维度
inputs = torch.randn(seq_len,batch_size,input_size)
hidden = torch.zeros(num_layers,batch_size,hidden_size)out,hidden = cell(inputs,hidden)print('Ouput size',out.shape)
print('Output:',out)
print('gidden size',hidden.shape)
print('hidden:',hidden)
3 hello->ohlol
3.1 代码实现
# 使用RNN
import torch
from torch import nn, optim
from torchvision import datasets
from torch.utils.data import DataLoader
from torchvision import transforms
import torch.nn.functional as F
import matplotlib.pyplot as pltinput_size = 4
hidden_size = 4
num_layers = 1
batch_size = 1
seq_len = 5
# 准备数据
idx2char = ['e', 'h', 'l', 'o']
x_data = [1, 0, 2, 2, 3] # hello
y_data = [3, 1, 2, 3, 2] # ohlolone_hot_lookup = [[1, 0, 0, 0],[0, 1, 0, 0],[0, 0, 1, 0],[0, 0, 0, 1]] # 分别对应0,1,2,3项
x_one_hot = [one_hot_lookup[x] for x in x_data] # 组成序列张量
print('x_one_hot:', x_one_hot)# 构造输入序列和标签
inputs = torch.Tensor(x_one_hot).view(seq_len, batch_size, input_size)
labels = torch.LongTensor(y_data) # labels维度是: (seqLen * batch_size ,1)# design model
class Model(torch.nn.Module):def __init__(self, input_size, hidden_size, batch_size, num_layers=1):super(Model, self).__init__()self.num_layers = num_layersself.batch_size = batch_sizeself.input_size = input_sizeself.hidden_size = hidden_sizeself.rnn = torch.nn.RNN(input_size=self.input_size,hidden_size=self.hidden_size,num_layers=self.num_layers)def forward(self, input):hidden = torch.zeros(self.num_layers, self.batch_size, self.hidden_size)out, _ = self.rnn(input, hidden)# 为了能和labels做交叉熵,需要reshape一下:(seqlen*batchsize, hidden_size),即二维向量,变成一个矩阵return out.view(-1, self.hidden_size)net = Model(input_size, hidden_size, batch_size, num_layers)# loss and optimizer
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.05)# train cycle
if __name__ == '__main__':epoch_list = []loss_list = []for epoch in range(20):optimizer.zero_grad()# inputs维度是: (seqLen, batch_size, input_size) labels维度是: (seqLen * batch_size * 1)# outputs维度是: (seqLen, batch_size, hidden_size)outputs = net(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()_, idx = outputs.max(dim=1)idx = idx.data.numpy()print('Predicted: ', ''.join([idx2char[x] for x in idx]), end='')print(',Epoch [%d/20] loss=%.3f' % (epoch + 1, loss.item()))epoch_list.append(epoch)loss_list.append(loss.item())plt.plot(epoch_list, loss_list)
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()
【刘二大人】PyTorch深度学习实践相关推荐
- 刘二大人 PyTorch深度学习实践 笔记 P6 逻辑斯蒂回归
刘二大人 PyTorch深度学习实践 笔记 P6 逻辑斯蒂回归 P6 逻辑斯蒂回归 1.torchversion 提供的数据集 2.基本概念 3.代码实现 P6 逻辑斯蒂回归 1.torchversi ...
- 【刘二大人 - PyTorch深度学习实践】学习随手记(一)
目录 1. Overview 1.Human Intelligence 2.Machine Learning 3.How to develop learning system? 4.Tradition ...
- 【Pytorch深度学习实践】B站up刘二大人之SoftmaxClassifier-代码理解与实现(8/9)
这是刘二大人系列课程笔记的倒数第二个博客了,介绍的是多分类器的原理和代码实现,下一个笔记就是basicCNN和advancedCNN了: 写在前面: 这节课的内容,主要是两个部分的修改: 一是数据集: ...
- PyTorch 深度学习实践 GPU版本B站 刘二大人第11讲卷积神经网络(高级篇)GPU版本
第11讲 卷积神经网络(高级篇) GPU版本源代码 原理是基于B站 刘二大人 :传送门PyTorch深度学习实践--卷积神经网络(高级篇) 这篇基于博主错错莫:传送门 深度学习实践 第11讲博文 仅在 ...
- 【Pytorch深度学习实践】B站up刘二大人之BasicCNN Advanced CNN -代码理解与实现(9/9)
这是刘二大人系列课程笔记的 最后一个笔记了,介绍的是 BasicCNN 和 AdvancedCNN ,我做图像,所以后面的RNN我可能暂时不会花时间去了解了: 写在前面: 本节把基础个高级CNN放在一 ...
- 笔记|(b站)刘二大人:pytorch深度学习实践(代码详细笔记,适合零基础)
pytorch深度学习实践 笔记中的代码是根据b站刘二大人的课程所做的笔记,代码每一行都有注释方便理解,可以配套刘二大人视频一同使用. 用PyTorch实现线性回归 # 1.算预测值 # 2.算los ...
- 【PyTorch深度学习实践 | 刘二大人】B站视频教程笔记
资料 [参考:<PyTorch深度学习实践>完结合集_哔哩哔哩_bilibili] [参考 分类专栏:PyTorch 深度学习实践_错错莫的博客-CSDN博客] 全[参考 分类专栏:PyT ...
- 【Pytorch深度学习实践】B站up刘二大人课程笔记——目录与索引(已完结)
从有代码的课程开始讨论 [Pytorch深度学习实践]B站up刘二大人之LinearModel -代码理解与实现(1/9) [Pytorch深度学习实践]B站up刘二大人之 Gradient Desc ...
- 【Pytorch深度学习实践】B站up刘二大人之 Gradient Descend-代码理解与实现(2/9)
开篇几句题外话: 以往的代码,都是随便看看就过去了,没有这样较真过,以至于看了很久的深度学习和Python,都没有能够形成编程能力: 这次算是废寝忘食的深入进去了,踏实地把每一个代码都理解透,包括其中 ...
最新文章
- 使用Django开发REST 接口
- [原创]前后端交互的方式整理
- 1020. Tree Traversals (25) PAT甲级真题
- 每天一道LeetCode-----计算给定序列中所有长度为k的滑动窗的最大值集合
- 干得累死,并不见得老板就待见你?
- 数学 :追求真和美的学问
- Hadoop伪集群部署
- 【安全牛学习笔记】初识sql注入漏洞原理
- 雷蛇灯光配置文件_突破极限!Razer雷蛇发布高性能V2版炼狱蝰蛇和巴塞利斯蛇...
- IV值区间与预测能力关系
- django实现上传头像和头像展示功能
- OpenStack 裸金属
- 如何设置下拉框多选以及设置多选值
- 网页设计中的灰色调配色技巧
- 用计算机和手算标准差不一致,统计基础知识与统计实务学习指导(2015版).doc
- 7-9 彩虹瓶 (25 分)(c++)
- js删除数组对象中的某个属性的方法
- 基于Java技术的大型网站架构设计方案
- Arduino人体红外感应+继电器
- 可满足性问题 SAT、3SAT
热门文章
- C语言的数据类型——基本数据类型——整形家族(字符类型)以及整形提升和截断
- [Paper Reading] Towards Conversational Recommendation over Multi-Type Dialogs
- Python2参考手册-方法
- PCB硬件设计之网口
- qq 飞信中无法切换输入法
- 关于Mac App Store无法下载、无法安装、一直转圈的解决方法
- 对于技术岗位而言,开发岗累还是算法岗累呢?
- 自动驾驶轨迹预测任务浅述
- python无法加载文件系统代码_致命的Python错误:initfsencoding:无法加载文件系统cod...
- 程序员12星座性格分析,猜猜哪个星座最适合IT行业?