当前位置:   article > 正文

[学习笔记] CNN与RNN方法结合

rnn与cnn结合 qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq

CNN与RNN的结合

问题

前几天学习了RNN的推导以及代码,那么问题来了,能不能把CNN和RNN结合起来,我们通过CNN提取的特征,能不能也将其看成一个序列呢?答案是可以的。

但是我觉得一般直接提取的特征喂给哦RNN训练意义是不大的,因为RNN擅长处理的是不定长的序列,也就是说,seq size是不确定的,但是一般图像特征的神经元数量都是定的,这个时候再接个rnn说实话意义不大,除非设计一种结构可以让网络不定长输出。(我的一个简单想法就是再设计一条之路去学习一个神经元权重mask,按照规则过滤掉一些神经元,然后丢进rnn或者lstm训练)

如何实现呢

  1. import torch
  2. import torch.nn as nn
  3. from torchsummary import summary
  4. from torchvision import datasets,transforms
  5. import torch.optim as optim
  6. from tqdm import tqdm
  7. class Model(nn.Module):
  8. def __init__(self):
  9. super(Model,self).__init__()
  10. self.feature_extractor = nn.Sequential(
  11. nn.Conv2d(1,16,kernel_size = 3,stride=2),
  12. nn.BatchNorm2d(16),
  13. nn.ReLU(),
  14. nn.Conv2d(16,64,kernel_size = 3,stride=2),
  15. nn.BatchNorm2d(64),
  16. nn.ReLU(),
  17. nn.Conv2d(64,128,kernel_size = 3,stride=2),
  18. nn.BatchNorm2d(128),
  19. nn.ReLU(),
  20. )
  21. self.rnn = nn.RNN(128,256,2) # input_size,output_size,hidden_num
  22. self.h0 = torch.zeros(2,32,256) # 层数 batchsize hidden_dim
  23. self.predictor = nn.Linear(4*256,10)
  24. def forward(self,x):
  25. x = self.feature_extractor(x) # (-1,128,2,2),4个神经元,128维度
  26. x,ht = self.rnn(x.permute(3,4,0,1).contiguous().view(4,-1,128),self.h0) # (h*w,batch_size,hidden_dim)
  27. x = self.predictor(x.view(-1,256*4))
  28. return x
  29. if __name__ == "__main__":
  30. model = Model()
  31. #summary(model,(1,28,28),device = "cpu")
  32. loss_fn = nn.CrossEntropyLoss()
  33. train_dataset = datasets.MNIST(root="./data/",train = True,transform = transforms.ToTensor(),download = True)
  34. test_dataset = datasets.MNIST(root="./data/",train = False,transform = transforms.ToTensor(),download = True)
  35. train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
  36. batch_size=32,
  37. shuffle=True)
  38. test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
  39. batch_size=128,
  40. shuffle=False)
  41. optimizer = optim.Adam(model.parameters(),lr = 1e-3)
  42. print(len(train_loader))
  43. for epoch in range(100):
  44. epoch_loss = 0.
  45. for x,target in train_loader:
  46. #print(x.size())
  47. y = model(x)
  48. loss = loss_fn(y,target)
  49. epoch_loss += loss.item()
  50. optimizer.zero_grad()
  51. loss.backward()
  52. optimizer.step()
  53. print("epoch : {} and loss is : {}".format(epoch +1,epoch_loss))
  54. torch.save(model.state_dict(),"rnn_cnn.pth")

上面代码可以看出我已经规定了RNN输入神经元的个数,所以肯定是定长的输入,我训练之后是可以收敛的。

对于不定长,其实还是没办法改变每个batch的seq len,因为规定的一定是最长的seq len,所以没办法做到真正的不定长。所以我能做的就是通过支路学习一个权重作用到原来的feature上去,这个权重是0-1权重,其实这样就可以达到效果了。

  1. import torch
  2. import torch.nn as nn
  3. from torchsummary import summary
  4. from torchvision import datasets,transforms
  5. import torch.optim as optim
  6. import torch.nn.functional as F
  7. from tqdm import tqdm
  8. class Model(nn.Module):
  9. def __init__(self):
  10. super(Model,self).__init__()
  11. self.feature_extractor = nn.Sequential(
  12. nn.Conv2d(1,16,kernel_size = 3,stride=2),
  13. nn.BatchNorm2d(16),
  14. nn.ReLU6(),
  15. nn.Conv2d(16,64,kernel_size = 3,stride=2),
  16. nn.BatchNorm2d(64),
  17. nn.ReLU6(),
  18. nn.Conv2d(64,128,kernel_size = 3,stride=2),
  19. nn.BatchNorm2d(128),
  20. nn.ReLU6(),
  21. )
  22. self.attn = nn.Conv2d(128,1,kernel_size = 1)
  23. self.rnn = nn.RNN(128,256,2) # input_size,output_size,hidden_num
  24. self.h0 = torch.zeros(2,32,256) # 层数 batchsize hidden_dim
  25. self.predictor = nn.Linear(4*256,10)
  26. def forward(self,x):
  27. x = self.feature_extractor(x) # (-1,128,2,2),4个神经元,128维度
  28. attn = F.relu(self.attn(x)) # (-1,1,2,2) -> (-1,4)
  29. x = x * attn
  30. #print(x.size())
  31. x,ht = self.rnn(x.permute(3,4,0,1).contiguous().view(4,-1,128),self.h0) # (h*w,batch_size,hidden_dim)
  32. #self.h0 = ht
  33. x = self.predictor(x.view(-1,256*4))
  34. return x
  35. if __name__ == "__main__":
  36. model = Model()
  37. #summary(model,(1,28,28),device = "cpu")
  38. #exit()
  39. loss_fn = nn.CrossEntropyLoss()
  40. train_dataset = datasets.MNIST(root="./data/",train = True,transform = transforms.ToTensor(),download = True)
  41. test_dataset = datasets.MNIST(root="./data/",train = False,transform = transforms.ToTensor(),download = True)
  42. train_loader = torch.utils.data.DataLoader(dataset=train_dataset,
  43. batch_size=32,
  44. shuffle=True)
  45. test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
  46. batch_size=128,
  47. shuffle=False)
  48. optimizer = optim.Adam(model.parameters(),lr = 1e-3)
  49. print(len(train_loader))
  50. for epoch in range(100):
  51. epoch_loss = 0.
  52. for x,target in train_loader:
  53. #print(x.size())
  54. y = model(x)
  55. loss = loss_fn(y,target)
  56. epoch_loss += loss.item()
  57. optimizer.zero_grad()
  58. loss.backward()
  59. optimizer.step()
  60. print("epoch : {} and loss is : {}".format(epoch +1,epoch_loss))
  61. torch.save(model.state_dict(),"rnn_cnn.pth")

我自己训练了一下,后者要比前者收敛的快的多。

转载于:https://www.cnblogs.com/aoru45/p/11576023.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/354543
推荐阅读
相关标签
  

闽ICP备14008679号