(Demo)

  • 这是最近两个月来的一个小总结,实现的demo已经上传github,里面包含了CNN、LSTM、BiLSTM、GRU以及CNN与LSTM、BiLSTM的结合还有多层多通道CNN、LSTM、BiLSTM等多个神经网络模型的的实现。这篇文章总结一下最近一段时间遇到的问题、处理方法和相关策略,以及经验(其实并没有什么经验)等,白菜一枚。

  • Demo Site:  https://github.com/bamtercelboo/cnn-lstm-bilstm-deepcnn-clstm-in-pytorch

(一) Pytorch简述

  • Pytorch是一个较新的深度学习框架,是一个 Python 优先的深度学习框架,能够在强大的 GPU 加速基础上实现张量和动态神经网络。

  • 对于没有学习过pytorch的初学者,可以先看一下官网发行的60分钟入门pytorch,参考地址 :http://pytorch.org/tutorials/beginner/deep_learning_60min_blitz.html

(二) CNN、LSTM

(三)数据预处理

  1、我现在使用的语料是基本规范的数据(例如下),但是加载语料数据的过程中仍然存在着一些需要预处理的地方,像一些数据的大小写、数字的处理以及“\n \t”等一些字符,现在使用torchtext第三方库进行加载数据预处理。

  • You Should Pay Nine Bucks for This : Because you can hear about suffering Afghan refugees on the news and still be unaffected . ||| 2
    Dramas like this make it human . ||| 4

  2、torch建立词表、处理语料数据的大小写:

  • import torchtext.data as data
    # lower word
    text_field = data.Field(lower=True)

  3、处理语料数据数字等特殊字符:

  •  from torchtext import data
    def clean_str(string):
    string = re.sub(r"[^A-Za-z0-9(),!?\'\`]", " ", string)
    string = re.sub(r"\'s", " \'s", string)
    string = re.sub(r"\'ve", " \'ve", string)
    string = re.sub(r"n\'t", " n\'t", string)
    string = re.sub(r"\'re", " \'re", string)
    string = re.sub(r"\'d", " \'d", string)
    string = re.sub(r"\'ll", " \'ll", string)
    string = re.sub(r",", " , ", string)
    string = re.sub(r"!", " ! ", string)
    string = re.sub(r"\(", " \( ", string)
    string = re.sub(r"\)", " \) ", string)
    string = re.sub(r"\?", " \? ", string)
    string = re.sub(r"\s{2,}", " ", string)
    return string.strip() text_field.preprocessing = data.Pipeline(clean_str)

  4、需要注意的地方:

  • 加载数据集的时候可以使用random打乱数据

  •  if shuffle:
    random.shuffle(examples_train)
    random.shuffle(examples_dev)
    random.shuffle(examples_test)
  • torchtext建立训练集、开发集、测试集迭代器的时候,可以选择在每次迭代的时候是否去打乱数据

  •  class Iterator(object):
    """Defines an iterator that loads batches of data from a Dataset. Attributes:
    dataset: The Dataset object to load Examples from.
    batch_size: Batch size.
    sort_key: A key to use for sorting examples in order to batch together
    examples with similar lengths and minimize padding. The sort_key
    provided to the Iterator constructor overrides the sort_key
    attribute of the Dataset, or defers to it if None.
    train: Whether the iterator represents a train set.
    repeat: Whether to repeat the iterator for multiple epochs.
    shuffle: Whether to shuffle examples between epochs.
    sort: Whether to sort examples according to self.sort_key.
    Note that repeat, shuffle, and sort default to train, train, and
    (not train).
    device: Device to create batches on. Use -1 for CPU and None for the
    currently active GPU device.
    """

(四)Word Embedding

  1、word embedding简单来说就是语料中每一个单词对应的其相应的词向量,目前训练词向量的方式最使用的应该是word2vec(参考 http://www.cnblogs.com/bamtercelboo/p/7181899.html

  2、上文中已经通过torchtext建立了相关的词汇表,加载词向量有两种方式,一个是加载外部根据语料训练好的预训练词向量,另一个方式是随机初始化词向量,两种方式相互比较的话当时是使用预训练好的词向量效果会好很多,但是自己训练的词向量并不见得会有很好的效果,因为语料数据可能不足,像已经训练好的词向量,像Google News那个词向量,是业界公认的词向量,但是由于数量巨大,如果硬件设施(GPU)不行的话,还是不要去尝试这个了。

  3、提供几个下载预训练词向量的地址

  4、加载外部词向量方式

  • 加载词汇表中在词向量里面能够找到的词向量

  •  # load word embedding
    def load_my_vecs(path, vocab, freqs):
    word_vecs = {}
    with open(path, encoding="utf-8") as f:
    count = 0
    lines = f.readlines()[1:]
    for line in lines:
    values = line.split(" ")
    word = values[0]
    # word = word.lower()
    count += 1
    if word in vocab: # whether to judge if in vocab
    vector = []
    for count, val in enumerate(values):
    if count == 0:
    continue
    vector.append(float(val))
    word_vecs[word] = vector
    return word_vecs
  • 处理词汇表中在词向量里面找不到的word,俗称OOV(out of vocabulary),OOV越多,可能对加过的影响也就越大,所以对OOV词的处理就显得尤为关键,现在有几种策略可以参考:
  • 对已经找到的词向量平均化

  •  # solve unknown by avg word embedding
    def add_unknown_words_by_avg(word_vecs, vocab, k=100):
    # solve unknown words inplaced by zero list
    word_vecs_numpy = []
    for word in vocab:
    if word in word_vecs:
    word_vecs_numpy.append(word_vecs[word])
    print(len(word_vecs_numpy))
    col = []
    for i in range(k):
    sum = 0.0
    # for j in range(int(len(word_vecs_numpy) / 4)):
    for j in range(int(len(word_vecs_numpy))):
    sum += word_vecs_numpy[j][i]
    sum = round(sum, 6)
    col.append(sum)
    zero = []
    for m in range(k):
    # avg = col[m] / (len(col) * 5)
    avg = col[m] / (len(word_vecs_numpy))
    avg = round(avg, 6)
    zero.append(float(avg)) list_word2vec = []
    oov = 0
    iov = 0
    for word in vocab:
    if word not in word_vecs:
    # word_vecs[word] = np.random.uniform(-0.25, 0.25, k).tolist()
    # word_vecs[word] = [0.0] * k
    oov += 1
    word_vecs[word] = zero
    list_word2vec.append(word_vecs[word])
    else:
    iov += 1
    list_word2vec.append(word_vecs[word])
    print("oov count", oov)
    print("iov count", iov)
    return list_word2vec
  • 随机初始化或者全部取zero,随机初始化或者是取zero,可以是所有的OOV都使用一个随机值,也可以每一个OOV word都是随机的,具体效果看自己效果

  • 随机初始化的值看过几篇论文,有的随机初始化是在(-0.25,0.25)或者是(-0.1,0.1)之间,具体的效果可以自己去测试一下,不同的数据集,不同的外部词向量估计效果不一样,我测试的结果是0.25要好于0.1

  •  # solve unknown word by uniform(-0.25,0.25)
    def add_unknown_words_by_uniform(word_vecs, vocab, k=100):
    list_word2vec = []
    oov = 0
    iov = 0
    # uniform = np.random.uniform(-0.25, 0.25, k).round(6).tolist()
    for word in vocab:
    if word not in word_vecs:
    oov += 1
    word_vecs[word] = np.random.uniform(-0.25, 0.25, k).round(6).tolist()
    # word_vecs[word] = np.random.uniform(-0.1, 0.1, k).round(6).tolist()
    # word_vecs[word] = uniform
    list_word2vec.append(word_vecs[word])
    else:
    iov += 1
    list_word2vec.append(word_vecs[word])
    print("oov count", oov)
    print("iov count", iov)
    return list_word2vec
  • 特别需要注意处理后的OOV词向量是否在一定的范围之内,这个一定要在处理之后手动或者是demo查看一下,想处理出来的词向量大于15,30的这种,可能就是你自己处理方式的问题,也可以是说是你自己demo可能存在bug,对结果的影响很大。

  5、model中使用外部词向量

  •          if args.word_Embedding:
    pretrained_weight = np.array(args.pretrained_weight)
    self.embed.weight.data.copy_(torch.from_numpy(pretrained_weight))

(五)参数初始化

  • 对于pytorch中的nn.Conv2d()卷积函数来说,有weight and bias,对weight初始化是很有必要的,不对其初始化可能减慢收敛速度,影响最终效果等

  • 对weight初始化,一般可以使用torch.nn.init.uniform()、torch.nn.init.normal()、torch.nn.init.xavier_uniform(),具体使用参考 http://pytorch.org/docs/master/nn.html#torch-nn-init

  •  init.xavier_normal(conv.weight.data, gain=np.sqrt(args.init_weight_value))
    init.uniform(conv.bias, 0, 0)
  • 对于pytorch中的nn.LSTM(),有all_weights属性,其中包括weight and bias,是一个多维矩阵

  •  if args.init_weight:
    print("Initing W .......")
    init.xavier_normal(self.bilstm.all_weights[0][0], gain=np.sqrt(args.init_weight_value))
    init.xavier_normal(self.bilstm.all_weights[0][1], gain=np.sqrt(args.init_weight_value))
    init.xavier_normal(self.bilstm.all_weights[1][0], gain=np.sqrt(args.init_weight_value))
    init.xavier_normal(self.bilstm.all_weights[1][1], gain=np.sqrt(args.init_weight_value))

(六)调参及其策略

  • 神经网络参数设置

  • CNN中的kernel-size:看过一篇paper(A Sensitivity Analysis of (and Practitioners’ Guide to)Convolutional Neural Networks for Sentence Classification),论文上测试了kernel的使用,根据其结果,设置大部分会在1-10随机组合,具体的效果还好根据自己的任务。

  • CNN中的kernel-num,就是每个卷积窗口的特征数目,大致设置在100-600,我一般会设置200,300

  • Dropout:Dropout大多数论文上设置都是0.5,据说0.5的效果很好,能够防止过拟合问题,但是在不同的task中,还需要适当的调整dropout的大小,出来要调整dropout值之外,dropout在model中的位置也是很关键的,可以尝试不同的dropout位置,或许会收到惊人的效果。

  • batch size:batch size这个还是需要去适当调整的,看相关的blogs,一般设置不会超过128,有可能也很小,在我目前的任务中,batch size =16有不错的效果。

  • learning rate:学习率这个一般初值对于不同的优化器设置是不一样的,据说有一些经典的配置,像Adam :lr = 0.001

  • 迭代次数:根据自己的task、model、收敛速度、拟合效果设置不同的值

  • LSTM中的hidden size:LSTM中的隐藏层维度大小也对结果有一定的影响,如果使用300dim的外部词向量的话,可以考虑hidden size =150或者是300,对于hidden size我最大设置过600,因为硬件设备的原因,600训练起来已经是很慢了,如果硬件资源ok的话,可以尝试更多的hidden size值,但是尝试的过程中还是要考虑一下hidden size 与词向量维度的关系(自认为其是有一定的关系影响的)

  • 二范式约束:pytorch中的Embedding中的max-norm  和norm-type就是二范式约束

  •  if args.max_norm is not None:
    print("max_norm = {} ".format(args.max_norm))
    self.embed = nn.Embedding(V, D, max_norm=args.max_norm)
  • pytorch中实现了L2正则化,也叫做权重衰减,具体实现是在优化器中,参数是 weight_decay(pytorch中的L1正则已经被遗弃了,可以自己实现),一般设置1e-8

  •  if args.Adam is True:
    print("Adam Training......")
    optimizer = torch.optim.Adam(model.parameters(), lr=args.lr, weight_decay=args.init_weight_decay)
  • 梯度消失、梯度爆炸问题

  •  import torch.nn.utils as utils
    if args.init_clip_max_norm is not None:
    utils.clip_grad_norm(model.parameters(),
    max_norm=args.init_clip_max_norm)
  • 神经网络提升Acc的策略

  • 数据预处理,建立词汇表的过程中可以把词频为1的单词剔除,这也是一个超参数,如果剔除之后发现准确率下降的话,可以尝试以一定的概率剔除或者是以一定的概率对这部分词向量进行不同的处理

  • 动态学习率:pytorch最新的版本0.2已经实现了动态学习率,具体使用参考 http://pytorch.org/docs/master/optim.html#how-to-adjust-learning-rate

  • 批量归一化(batch normalizations),pytorch中也提供了相应的函数 BatchNorm1d() 、BatchNorm2d() 可以直接使用,其中有一个参数(momentum)可以作为超参数调整

  •  if args.batch_normalizations is True:
    print("using batch_normalizations in the model......")
    self.convs1_bn = nn.BatchNorm2d(num_features=Co, momentum=args.bath_norm_momentum,
    affine=args.batch_norm_affine)
    self.fc1_bn = nn.BatchNorm1d(num_features=in_fea//2, momentum=args.bath_norm_momentum,
    affine=args.batch_norm_affine)
    self.fc2_bn = nn.BatchNorm1d(num_features=C, momentum=args.bath_norm_momentum,
    affine=args.batch_norm_affine)
  • 宽卷积、窄卷积,在深层卷积model中应该需要使用的是宽卷积,使用窄卷积的话会出现维度问题,我现在使用的数据使用双层卷积神经网络就会出现维度问题,其实也是和数据相关的

  •  if args.wide_conv is True:
    print("using wide convolution")
    self.convs1 = [nn.Conv2d(in_channels=Ci, out_channels=Co, kernel_size=(K, D), stride=(1, 1),
    padding=(K//2, 0), dilation=1, bias=True) for K in Ks]
    else:
    print("using narrow convolution")
    self.convs1 = [nn.Conv2d(in_channels=Ci, out_channels=Co, kernel_size=(K, D), bias=True) for K in Ks]
  • character-level的处理,最开始的处理方式是使用词进行处理(也就是单词),可以考虑根据字符去划分,划分出来的词向量可以采用随机初始化的方式,这也是一种策略,我试过这种策略,对我目前的任务来说是没有提升的。

  • 优化器:pytorch提供了多个优化器,我们最常用的是Adam,效果还是很不错的,具体的可以参考 http://pytorch.org/docs/master/optim.html#algorithms

  • fine-tune or no-fine-tune:这是一个很重要的策略,一般情况下fine-tune是有很不错的效果的相对于no-fine-tune来说。

(七)参考致谢

(END)欢迎各位转载,但请指明出处 bamtercelboo

 if args.init_weight:
print("Initing W .......")
init.xavier_normal(self.bilstm.all_weights[0][0], gain=np.sqrt(args.init_weight_value))
init.xavier_normal(self.bilstm.all_weights[0][1], gain=np.sqrt(args.init_weight_value))
init.xavier_normal(self.bilstm.all_weights[1][0], gain=np.sqrt(args.init_weight_value))
init.xavier_normal(self.bilstm.all_weights[1][1], gain=np.sqrt(args.init_wei
 if shuffle:
random.shuffle(examples_train)
random.shuffle(examples_dev)
random.shuffle(examples,

基于pytorch的CNN、LSTM神经网络模型调参小结的更多相关文章

  1. scikit-learn随机森林调参小结

    在Bagging与随机森林算法原理小结中,我们对随机森林(Random Forest, 以下简称RF)的原理做了总结.本文就从实践的角度对RF做一个总结.重点讲述scikit-learn中RF的调参注 ...

  2. rf调参小结

    转自http://www.cnblogs.com/pinard/p/6160412.html 1. scikit-learn随机森林类库概述 在scikit-learn中,RF的分类类是RandomF ...

  3. 使用PyTorch简单实现卷积神经网络模型

    这里我们会用 Python 实现三个简单的卷积神经网络模型:LeNet .AlexNet .VGGNet,首先我们需要了解三大基础数据集:MNIST 数据集.Cifar 数据集和 ImageNet 数 ...

  4. scikit-learn 梯度提升树(GBDT)调参小结

    在梯度提升树(GBDT)原理小结中,我们对GBDT的原理做了总结,本文我们就从scikit-learn里GBDT的类库使用方法作一个总结,主要会关注调参中的一些要点. 1. scikit-learn ...

  5. 转pytorch中训练深度神经网络模型的关键知识点

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_42279044/articl ...

  6. GBDT调参总结

    一.GBDT类库弱学习器参数 二.回归 数据集:已知用户的30个特征,预测用户的信用值 from sklearn.ensemble import GradientBoostingRegressor f ...

  7. 深度学习之PyTorch实战(2)——神经网络模型搭建和参数优化

    上一篇博客先搭建了基础环境,并熟悉了基础知识,本节基于此,再进行深一步的学习. 接下来看看如何基于PyTorch深度学习框架用简单快捷的方式搭建出复杂的神经网络模型,同时让模型参数的优化方法趋于高效. ...

  8. 使用PyTorch构建神经网络模型进行手写识别

    使用PyTorch构建神经网络模型进行手写识别 PyTorch是一种基于Torch库的开源机器学习库,应用于计算机视觉和自然语言处理等应用,本章内容将从安装以及通过Torch构建基础的神经网络,计算梯 ...

  9. 手写数字识别 ----卷积神经网络模型官方案例注释(基于Tensorflow,Python)

    # 手写数字识别 ----卷积神经网络模型 import os import tensorflow as tf #部分注释来源于 # http://www.cnblogs.com/rgvb178/p/ ...

随机推荐

  1. linux 的一些脑洞操作

    把当前文件夹的文件名用","连接成一行,或者将多行转变为一行 ls | paste -s -d "," # -s 选项将输入进行一次性粘贴 ls | xargs ...

  2. 博弈论之Nim游戏

    Nim游戏是组合游戏(Combinatorial Games)的一种,属于“Impartial Combinatorial Games”(以下简称ICG). 通常的Nim游戏的定义是这样的:有若干堆石 ...

  3. 设计模式-策略模式Strategy以及消灭if else

    概述 如果在开发过程中,出现大量的if else或者switch case 语句,如果这些语句块中的代码并不是包含业务逻辑,只是单纯的分流方法,那么,每一个语句块中都是一个算法或者叫策略. 背景 比如 ...

  4. spring-boot整合mybatis(1)

    sprig-boot是一个微服务架构,加快了spring工程快速开发,以及简便了配置.接下来开始spring-boot与mybatis的整合. 1.创建一个maven工程命名为spring-boot- ...

  5. 使用Visual Studio Code调试基于ActionScript的LayaAir HTML5游戏

    使用Visual Studio Code(VS Code)调试的优势 使用VS Code我们可以极大地提高LayaAir Html5游戏项目的调试效率,VS Code的优势有以下几点: 在发生Java ...

  6. 【学习OpenCV】——2.4对图像进行平滑处理

    作者基于WIN10+VS2015+OpenCV3.0.0 (本人在学习的时候参考了xiahouzuoxin 的有关文章,在此感谢 ) 图像平滑与图像模糊是同一概念,主要用于图像的去噪.平滑要使用滤波器 ...

  7. linux C语言处理正则表达式

    Linux下C语言处理正则表达式——regex.h 具体函数介绍 编译正则表达式函数 int regcomp(regex_t *preg, const char *regex, int cflags) ...

  8. sshpass做秘钥分发,ansible做自动化运维工具

    最近公司机器的增多,顺便还要上报表系统,考虑到服务器越来越多,手工的管理显得越来的越吃力,所以打算推进公司自动化运维工具的使用. 推进的过程中,一步一个坑踩过来的.由于公司之前未运用过自动化运维工具, ...

  9. 分辨率验证工具 - 【Window Resizer】的使用 - Google扩展工具

    # 今天在Firefox上面安装"The Addon Bar"未果,于是转战Google了 # 想说的是http://cn.bing.com/ 简直太好用了 软件名称:Window Resizer 安 ...

  10. getNextElement( )函数——获取下一个特定的元素节点

    function getNextElement(node){ //定义getNextElement()函数 if (node.nodeType==){ //条件:如果node参数nodetype属性为 ...