• NLP-Beginner:自然语言处理入门练习----task 2基于机器学习的文本分类


    数据集:http://链接:https://pan.baidu.com/s/1UIrk148uRGWKQBBQp-Q4RQ 提取码:o13v

    上方为glove数据集。

    任务:

    1.熟悉Pytorch,用Pytorch重写《任务一》,实现CNN、RNN的文本分类

    2.word embedding 的方式初始化

    3.随机embedding的初始化方式

    4.用glove 预训练的embedding进行初始化

     GloVe: Global Vectors for Word Representation

    一、知识点:

    1.word embedding(词嵌入):词嵌入模型即是把每一个词映射到一个高维空间里,每一个词代表着一个高维空间的向量词嵌入实际上是一类技术,单个词在预定义的向量空间中被表示为实数向量,每个单词都映射到一个向量。举个例子,比如在一个文本中包含“猫”“狗”“爱情”等若干单词,而这若干单词映射到向量空间中,“猫”对应的向量为(0.1 0.2 0.3),“狗”对应的向量为(0.2 0.2 0.4),“爱情”对应的映射为(-0.4 -0.5 -0.2)(本数据仅为示意)。像这种将文本X{x1,x2,x3,x4,x5……xn}映射到多维向量空间Y{y1,y2,y3,y4,y5……yn },这个映射的过程就叫做词嵌入。通过词嵌入这种方式将单词转变为词向量,机器便可对单词进行计算,通过计算不同词向量之间夹角余弦值cos而得出单词之间的相似性。

    词嵌入模型的初始化:

    (1)随机初始化:给定一个维度d,对于每一个词,随机生成一个d维的向量。这种初始方式非常简单,但是相对可能会产生较劣的初值,也没有一个良好的解释性。

    (2)预训练模型初始化(Glove):拿别人已经训练好的模型作为初值,初始化时间会比较长,因为要从别人的词库里面找,但是这种初值无疑要比随机初始化好得多。

    特征表示:给定每个词的词向量,可以把一个句子量化成一个ID列表,再变成特征,也就是矩阵,得到句子的特征矩阵X后,便可以把它放到神经网络中。

    2.CNN/RNN

    1. CNN卷积神经网络:一般有3-4层,分别是卷积层,激活层,池化层,全连接层,具有局部连接,权重共享,汇聚等特性的深层前馈神经网络,这里的激活参数选择了ReLU函数,ReLu(x)=max(x,0)池化层相当于是对特征矩阵/向量提取出一些有用的信息,从而减少特征的规模,不仅减少了计算量,也能去除冗余特征。
    2. RNN循环神经网络:一般有2-3层,分别是隐藏层,激活曾,全连接层,具有短期记忆能力的神经网络。隐藏层的目的是为了实现记忆功能。

    在CNN中,是直接对特征矩阵X进行操作,而在RNN中,是逐个对xi进行操作。

    整个流程:句子x通过word embedding得出特征矩阵X在通过神经网络得到类别概率向量p。

    3.Dropout(丢弃法)

    Dropout (丢弃法) 是指在深度网络的训练中,以一定的概率随机地“临时丢弃”一部分神经元节点。 具体来讲,Dropout 作用于每份小批量训练数据,由于其随机丢弃部分神经元的机制,相当于每次迭代都在训练不同结构的神经网络。简单来讲,就是为了防止模型过拟合,且Dropout层在模型测试时不会有任何影响

    二、实验数据设置

    样本个数:约150000;

    训练集:测试集: 7:3

    alpha:10-3

    lh,d:50

    ll:最长句子的单词数目

    Batch大小:500

    三、代码

    1.main.py

    1. # -*- coding: GBK -*-
    2. # -*- coding: UTF-8 -*-
    3. # coding=gbk
    4. import csv
    5. import random
    6. from feature import Random_embedding,Glove_embedding
    7. from comparison_plot import NN_embedding_plot
    8. # 数据读入
    9. with open('train.tsv') as f :
    10. tsvreader = csv.reader(f,delimiter='\t')
    11. temp = list(tsvreader)
    12. with open('glove.6B.50d.txt','rb') as f: # glove embedding
    13. lines = f.readlines()
    14. # 用Glove创建词典
    15. trained_dict = dict()
    16. n = len(lines) # lines的长度
    17. for i in range(n): # 遍历
    18. line = lines[i].split() # split分割 upper大写
    19. trained_dict[line[0].decode('utf-8').upper()] = [float(line[j]) for j in range(1,51)]
    20. # 初始化
    21. iter_times = 50 # 做50个epoch
    22. alpha = 0.001 # 学习率
    23. # 程序开始
    24. data = temp[1:]
    25. batch_size = 500 # 批大小
    26. # 随机初始化
    27. random.seed(2021) # 随机种子
    28. random_embedding = Random_embedding(data=data ) # 调用feature
    29. random_embedding.get_words() # 找到所有单词,并标记ID
    30. random_embedding.get_id() # 找到每个句子拥有的单词ID
    31. # 预训练模型初始化
    32. random.seed(2021)
    33. glove_embedding = Glove_embedding(data=data,trained_dict=trained_dict)
    34. glove_embedding.get_words() # 找到所有单词并标记ID
    35. glove_embedding.get_id() # 找到每个句子拥有的单词ID
    36. NN_embedding_plot(random_embedding,glove_embedding,alpha,batch_size,iter_times)

    2.feature.py

    1. # -*- coding: GBK -*-
    2. # -*- coding: UTF-8 -*-
    3. # coding=gbk
    4. # 特征提取
    5. import random
    6. from torch.utils.data import Dataset,DataLoader
    7. from torch.nn.utils.rnn import pad_sequence
    8. import torch
    9. # 将数据按照一定的比例分割为训练集和测试集
    10. def data_split(data,test_rate=0.3):
    11. train = list()
    12. test = list()
    13. for datum in data:
    14. if random.random() > test_rate:
    15. train.append(datum)
    16. else:
    17. test.append(datum)
    18. return train,test
    19. # 随机初始化
    20. class Random_embedding():
    21. def __init__(self,data,test_rate=0.3):
    22. self.dict_words = dict() # 单词->ID的映射
    23. data.sort(key=lambda x:len(x[2].split())) # 按照句子长度排序,短着在前,这样做可以避免后面一个batch内句子长短不一,导致padding过度
    24. self.data = data
    25. self.len_words = 0 # 单词数目(包括padding的ID:0)
    26. self.train,self.test = data_split(data,test_rate=test_rate) # 训练集测试集划分
    27. self.train_y = [int(term[3]) for term in self.train] # 训练集类别
    28. self.test_y = [int(term[3]) for term in self.test] # 测试集类别
    29. self.train_matrix = list() # 训练集的单词ID列表,叠成一个矩阵
    30. self.test_matrix = list() # 测试集的单词ID列表,叠成一个矩阵
    31. self.longest = 0 # 记录最长的单词
    32. def get_words(self):
    33. for term in self.data:
    34. s = term[2] # 取出句子
    35. s = s.upper() # 将其转化为大写,避免识别i和I为不同的两个单词
    36. words = s.split()
    37. for word in words: # 一个一个单词进行寻找
    38. if word not in self.dict_words:
    39. self.dict_words[word] = len(self.dict_words) + 1 # padding是第0个,所以要+1
    40. self.len_words = len(self.dict_words) # 单词数目,暂未包括padding的id0
    41. def get_id(self):
    42. for term in self.train: # 训练集
    43. s = term[2]
    44. s = s.upper()
    45. words = s.split()
    46. item = [self.dict_words[word] for word in words] # 找到id列表(未进行padding)
    47. self.longest = max(self.longest,len(item)) # 记录最长的单词
    48. self.train_matrix.append(item)
    49. for term in self.test: # 测试集
    50. s = term[2]
    51. s = s.upper()
    52. words = s.split()
    53. item = [self.dict_words[word] for word in words] # 找到id列表(未进行padding)
    54. self.longest = max(self.longest,len(item))
    55. self.test_matrix.append(item)
    56. self.len_words += 1 # 单词数目,包含padding的id0
    57. class Glove_embedding():
    58. def __init__(self,data,trained_dict,test_rate=0.3):
    59. self.dict_words = dict() # 单词->ID的映射
    60. self.trained_dict = trained_dict # 记录预训练词向量模型
    61. data.sort(key = lambda x:len(x[2].split())) # 按照句子长度排序,短着在前,这样做可以避免后面一个batch内句子长短不一,导致padding过度
    62. self.data = data
    63. self.len_words = 0 # 单词数目(包含padding的id0)
    64. self.train,self.test = data_split(data,test_rate=test_rate) # 测试集和训练集的划分
    65. self.train_y = [int(term[3]) for term in self.train] # 训练集类别
    66. self.test_y = [int(term[3]) for term in self.test] # 测试集类别
    67. self.train_matrix = list()
    68. self.test_matrix = list()
    69. self.longest = 0
    70. self.embedding = list() # 抽取出用到的,即预训练模型的单词
    71. def get_words(self):
    72. self.embedding.append([0] * 50) # 先加padding的词向量
    73. for term in self.data:
    74. s = term[2] # 取出句子
    75. s = s.upper()
    76. words = s.split()
    77. for word in words:
    78. if word not in self.dict_words:
    79. self.dict_words[word] = len(self.dict_words)+1 # padding是第0个所以要加一
    80. if word in self.trained_dict: # 如果预训练模型中有这个单词,直接记录词向量
    81. self.embedding.append(self.trained_dict[word])
    82. else: # 如果预训练模型中没有这个单词,则初始化该词的对应词向量为0向量
    83. self.embedding.append([0]*50)
    84. self.len_words = len(self.dict_words) # 单词数目(暂未包括padding的id0)
    85. def get_id(self):
    86. for term in self.train: # 训练集
    87. s = term[2]
    88. s = s.upper()
    89. words = s.split()
    90. item = [self.dict_words[word] for word in words] # 找到id列表(未进行padding)
    91. self.longest = max(self.longest,len(item)) # 记录最长的单词
    92. self.train_matrix.append(item)
    93. for term in self.test: # 测试集
    94. s = term[2]
    95. s = s.upper()
    96. words = s.split()
    97. item = [self.dict_words[word] for word in words]
    98. self.longest = max(self.longest,len(item))
    99. self.test_matrix.append(item)
    100. self.len_words += 1 # 单词数目(暂未包括padding的id0)
    101. # 自定义数据集的结构
    102. class ClsDataset(Dataset):
    103. def __init__(self,sentence,emotion):
    104. self.sentence = sentence
    105. self.emotion = emotion
    106. def __getitem__(self, item):
    107. return self.sentence[item],self.emotion[item]
    108. def __len__(self):
    109. return len(self.emotion)
    110. # 自定义数据集的内数据返回类型,并进行padding
    111. def collate_fn(batch_data):
    112. sentence,emotion = zip(*batch_data)
    113. sentences = [torch.LongTensor(sent) for sent in sentence] # 把句子变成LongTensor类型
    114. padded_sents = pad_sequence(sentences,batch_first=True,padding_value=0) # 自动padding操作
    115. return torch.LongTensor(padded_sents),torch.LongTensor(emotion)
    116. # 利用dataloader划分batch
    117. def get_batch(x,y,batch_size):
    118. dataset = ClsDataset(x,y)
    119. dataloader = DataLoader(dataset,batch_size=batch_size,shuffle=False,drop_last=True,collate_fn=collate_fn)
    120. return dataloader
    121. # shuffle是指每个epoch都随机打乱数据再分batch,设置成False,否则之前的顺序会直接打乱
    122. # drop_last是指不利用最后一个不完整的batch(数据大小不能被batch_size整除)

    3.comparison_plot.py

    1. # -*- coding: GBK -*-
    2. # -*- coding: UTF-8 -*-
    3. # coding=gbk
    4. import matplotlib.pyplot
    5. import torch
    6. import torch.nn.functional as F
    7. from torch import optim
    8. from Neural_network import RNN, CNN
    9. from feature import get_batch
    10. def NN_embdding(model, train, test, learning_rate, iter_times):
    11. # 定义优化器(求参数)
    12. optimizer = optim.Adam(model.parameters(), lr=learning_rate)
    13. # 损失函数
    14. loss_fun = F.cross_entropy
    15. # 损失值记录
    16. train_loss_record = list()
    17. test_loss_record = list()
    18. long_loss_record = list()
    19. # 准确率记录
    20. train_record = list()
    21. test_record = list()
    22. long_record = list()
    23. # torch.autograd.set_detect_anomaly(True)
    24. # 训练阶段
    25. for iteration in range(iter_times):
    26. model.train() # 重要!!!进入非训练模式
    27. for i, batch in enumerate(train):
    28. x, y = batch # 取一个batch
    29. # y = y.cuda()
    30. pred = model(x) # 计算输出
    31. optimizer.zero_grad() # 梯度初始化
    32. loss = loss_fun(pred, y) # 损失值计算
    33. loss.backward() # 反向传播梯度
    34. optimizer.step() # 更新参数
    35. model.eval() # 重要!!!进入非训练模式(测试模式)
    36. # 本轮正确率记录
    37. train_acc = list()
    38. test_acc = list()
    39. long_acc = list()
    40. length = 20
    41. # 本轮损失值记录
    42. train_loss = 0
    43. test_loss = 0
    44. long_loss = 0
    45. for i, batch in enumerate(train):
    46. x, y = batch # 取一个batch
    47. # y = y.cuda()
    48. pred = model(x) # 计算输出
    49. loss = loss_fun(pred, y) # 损失值计算
    50. train_loss += loss.item() # 损失值累加
    51. _, y_pre = torch.max(pred, -1)
    52. # 计算本batch准确率
    53. acc = torch.mean((torch.tensor(y_pre == y, dtype=torch.float)))
    54. train_acc.append(acc)
    55. for i, batch in enumerate(test):
    56. x, y = batch # 取一个batch
    57. # y = y.cuda()
    58. pred = model(x) # 计算输出
    59. loss = loss_fun(pred, y) # 损失值计算
    60. test_loss += loss.item() # 损失值累加
    61. _, y_pre = torch.max(pred, -1)
    62. # 计算本batch准确率
    63. acc = torch.mean((torch.tensor(y_pre == y, dtype=torch.float)))
    64. test_acc.append(acc)
    65. if (len(x[0])) > length: # 长句子侦测
    66. long_acc.append(acc)
    67. long_loss += loss.item()
    68. trains_acc = sum(train_acc) / len(train_acc)
    69. tests_acc = sum(test_acc) / len(test_acc)
    70. longs_acc = sum(long_acc) / len(long_acc)
    71. train_loss_record.append(train_loss / len(train_acc))
    72. test_loss_record.append(test_loss / len(test_acc))
    73. long_loss_record.append(long_loss / len(long_acc))
    74. train_record.append(trains_acc)
    75. test_record.append(tests_acc)
    76. long_record.append(longs_acc)
    77. print("---------- Iteration", iteration + 1, "----------")
    78. print("Train loss:", train_loss / len(train_acc))
    79. print("Test loss:", test_loss / len(test_acc))
    80. print("Train accuracy:", trains_acc)
    81. print("Test accuracy:", tests_acc)
    82. print("Long sentence accuracy:", longs_acc)
    83. return train_loss_record, test_loss_record, long_loss_record, train_record, test_record, long_record
    84. def NN_embedding_plot(random_embedding, glove_embedding, learning_rate, batch_size, iter_times):
    85. # 获得训练集和测试集的batch
    86. train_random = get_batch(random_embedding.train_matrix,
    87. random_embedding.train_y, batch_size)
    88. test_random = get_batch(random_embedding.test_matrix,
    89. random_embedding.test_y, batch_size)
    90. train_glove = get_batch(glove_embedding.train_matrix,
    91. glove_embedding.train_y, batch_size)
    92. test_glove = get_batch(random_embedding.test_matrix,
    93. glove_embedding.test_y, batch_size)
    94. # 模型建立
    95. torch.manual_seed(2021)
    96. torch.manual_seed(2021)
    97. random_rnn = RNN(50, 50, random_embedding.len_words)
    98. torch.manual_seed(2021)
    99. torch.manual_seed(2021)
    100. random_cnn = CNN(50, random_embedding.len_words, random_embedding.longest)
    101. torch.manual_seed(2021)
    102. torch.manual_seed(2021)
    103. glove_rnn = RNN(50, 50, glove_embedding.len_words,
    104. weight=torch.tensor(glove_embedding.embedding, dtype=torch.float))
    105. torch.manual_seed(2021)
    106. torch.manual_seed(2021)
    107. glove_cnn = CNN(50, glove_embedding.len_words, glove_embedding.longest,
    108. weight=torch.tensor(glove_embedding.embedding, dtype=torch.float))
    109. # rnn+random
    110. torch.manual_seed(2021)
    111. torch.manual_seed(2021)
    112. trl_ran_rnn, tel_ran_rnn, lol_ran_rnn, tra_ran_rnn, tes_ran_rnn, lon_ran_rnn = \
    113. NN_embdding(random_rnn, train_random, test_random, learning_rate, iter_times)
    114. # cnn+random
    115. torch.manual_seed(2021)
    116. torch.manual_seed(2021)
    117. trl_ran_cnn, tel_ran_cnn, lol_ran_cnn, tra_ran_cnn, tes_ran_cnn, lon_ran_cnn = \
    118. NN_embdding(random_cnn, train_random, test_random, learning_rate, iter_times)
    119. # rnn+glove
    120. torch.manual_seed(2021)
    121. torch.manual_seed(2021)
    122. trl_glo_rnn, tel_glo_rnn, lol_glo_rnn, tra_glo_rnn, tes_glo_rnn, lon_glo_rnn = \
    123. NN_embdding(glove_rnn, train_glove, test_glove, learning_rate, iter_times)
    124. # cnn+glove
    125. torch.manual_seed(2021)
    126. torch.manual_seed(2021)
    127. trl_glo_cnn, tel_glo_cnn, lol_glo_cnn, tra_glo_cnn, tes_glo_cnn, lon_glo_cnn = \
    128. NN_embdding(glove_cnn, train_glove, test_glove, learning_rate, iter_times)
    129. # 画图部分
    130. x = list(range(1, iter_times + 1))
    131. matplotlib.pyplot.subplot(2, 2, 1)
    132. matplotlib.pyplot.plot(x, trl_ran_rnn, 'r--', label='RNN+random')
    133. matplotlib.pyplot.plot(x, trl_ran_cnn, 'g--', label='CNN+random')
    134. matplotlib.pyplot.plot(x, trl_glo_rnn, 'b--', label='RNN+glove')
    135. matplotlib.pyplot.plot(x, trl_glo_cnn, 'y--', label='CNN+glove')
    136. matplotlib.pyplot.legend()
    137. matplotlib.pyplot.legend(fontsize=10)
    138. matplotlib.pyplot.title("Train Loss")
    139. matplotlib.pyplot.xlabel("Iterations")
    140. matplotlib.pyplot.ylabel("Loss")
    141. matplotlib.pyplot.subplot(2, 2, 2)
    142. matplotlib.pyplot.plot(x, tel_ran_rnn, 'r--', label='RNN+random')
    143. matplotlib.pyplot.plot(x, tel_ran_cnn, 'g--', label='CNN+random')
    144. matplotlib.pyplot.plot(x, tel_glo_rnn, 'b--', label='RNN+glove')
    145. matplotlib.pyplot.plot(x, tel_glo_cnn, 'y--', label='CNN+glove')
    146. matplotlib.pyplot.legend()
    147. matplotlib.pyplot.legend(fontsize=10)
    148. matplotlib.pyplot.title("Test Loss")
    149. matplotlib.pyplot.xlabel("Iterations")
    150. matplotlib.pyplot.ylabel("Loss")
    151. matplotlib.pyplot.subplot(2, 2, 3)
    152. matplotlib.pyplot.plot(x, tra_ran_rnn, 'r--', label='RNN+random')
    153. matplotlib.pyplot.plot(x, tra_ran_cnn, 'g--', label='CNN+random')
    154. matplotlib.pyplot.plot(x, tra_glo_rnn, 'b--', label='RNN+glove')
    155. matplotlib.pyplot.plot(x, tra_glo_cnn, 'y--', label='CNN+glove')
    156. matplotlib.pyplot.legend()
    157. matplotlib.pyplot.legend(fontsize=10)
    158. matplotlib.pyplot.title("Train Accuracy")
    159. matplotlib.pyplot.xlabel("Iterations")
    160. matplotlib.pyplot.ylabel("Accuracy")
    161. matplotlib.pyplot.ylim(0, 1)
    162. matplotlib.pyplot.subplot(2, 2, 4)
    163. matplotlib.pyplot.plot(x, tes_ran_rnn, 'r--', label='RNN+random')
    164. matplotlib.pyplot.plot(x, tes_ran_cnn, 'g--', label='CNN+random')
    165. matplotlib.pyplot.plot(x, tes_glo_rnn, 'b--', label='RNN+glove')
    166. matplotlib.pyplot.plot(x, tes_glo_cnn, 'y--', label='CNN+glove')
    167. matplotlib.pyplot.legend()
    168. matplotlib.pyplot.legend(fontsize=10)
    169. matplotlib.pyplot.title("Test Accuracy")
    170. matplotlib.pyplot.xlabel("Iterations")
    171. matplotlib.pyplot.ylabel("Accuracy")
    172. matplotlib.pyplot.ylim(0, 1)
    173. matplotlib.pyplot.tight_layout()
    174. fig = matplotlib.pyplot.gcf()
    175. fig.set_size_inches(8, 8, forward=True)
    176. matplotlib.pyplot.savefig('main_plot.jpg')
    177. matplotlib.pyplot.show()
    178. matplotlib.pyplot.subplot(2, 1, 1)
    179. matplotlib.pyplot.plot(x, lon_ran_rnn, 'r--', label='RNN+random')
    180. matplotlib.pyplot.plot(x, lon_ran_cnn, 'g--', label='CNN+random')
    181. matplotlib.pyplot.plot(x, lon_glo_rnn, 'b--', label='RNN+glove')
    182. matplotlib.pyplot.plot(x, lon_glo_cnn, 'y--', label='CNN+glove')
    183. matplotlib.pyplot.legend()
    184. matplotlib.pyplot.legend(fontsize=10)
    185. matplotlib.pyplot.title("Long Sentence Accuracy")
    186. matplotlib.pyplot.xlabel("Iterations")
    187. matplotlib.pyplot.ylabel("Accuracy")
    188. matplotlib.pyplot.ylim(0, 1)
    189. matplotlib.pyplot.subplot(2, 1, 2)
    190. matplotlib.pyplot.plot(x, lol_ran_rnn, 'r--', label='RNN+random')
    191. matplotlib.pyplot.plot(x, lol_ran_cnn, 'g--', label='CNN+random')
    192. matplotlib.pyplot.plot(x, lol_glo_rnn, 'b--', label='RNN+glove')
    193. matplotlib.pyplot.plot(x, lol_glo_cnn, 'y--', label='CNN+glove')
    194. matplotlib.pyplot.legend()
    195. matplotlib.pyplot.legend(fontsize=10)
    196. matplotlib.pyplot.title("Long Sentence Loss")
    197. matplotlib.pyplot.xlabel("Iterations")
    198. matplotlib.pyplot.ylabel("Loss")
    199. matplotlib.pyplot.tight_layout()
    200. fig = matplotlib.pyplot.gcf()
    201. fig.set_size_inches(8, 8, forward=True)
    202. matplotlib.pyplot.savefig('sub_plot.jpg')
    203. matplotlib.pyplot.show()

    4.Neural_network.py

    1. # -*- coding: GBK -*-
    2. # -*- coding: UTF-8 -*-
    3. # coding=gbk
    4. import torch
    5. import torch.nn as nn
    6. import torch.nn.functional as F
    7. # 设计RNN网络
    8. class RNN(nn.Module):
    9. def __init__(self,len_feature,len_hidden,len_words,typenum=5,weight=None,layer=1,nonlinearity='tanh',batch_first=True,drop_out=0.5):
    10. super(RNN, self).__init__()
    11. self.len_feature = len_feature # d的大小
    12. self.len_hidden = len_hidden # l_h的大小
    13. self.len_words = len_words # 单词的个数,包含padding
    14. self.layer = layer # 隐藏层层数
    15. self.dropout = nn.Dropout(drop_out) # dropout层
    16. if weight is None: # 随机初始化
    17. x = nn.init.xavier_normal_(torch.Tensor(len_words,len_feature))
    18. self.embedding = nn.Embedding(num_embeddings=len_words,embedding_dim=len_feature,_weight=x)
    19. else: # Glove初始化
    20. self.embedding = nn.Embedding(num_embeddings=len_words,embedding_dim=len_feature,_weight=weight)
    21. # 用nn.Module的内置函数定义隐藏层
    22. self.rnn = nn.RNN(input_size=len_feature,hidden_size=len_hidden,num_layers=layer,nonlinearity=nonlinearity,batch_first=batch_first,dropout=drop_out)
    23. # 全连接层
    24. self.fc = nn.Linear(len_hidden,typenum)
    25. # softmax层冗余,可以不加
    26. # self.act = nn.softmax(dim=1)
    27. def forward(self,x):
    28. # x:数据,维度为[batch_size,句子长度]
    29. x = torch.LongTensor(x)
    30. batch_size = x.size(0)
    31. # 经过词嵌入后,维度为[batch_size,句子长度,d]
    32. out_put = self.embedding(x) # 词嵌入
    33. out_put = self.dropout(out_put) # dropout层
    34. h0 = torch.autograd.Variable(torch.zeros(self.layer,batch_size,self.len_hidden))
    35. # dropout层不变,经过隐藏层后,维度变成[1,batch_size,l_h]
    36. _,hn = self.rnn(out_put,h0) # 隐藏层计算
    37. # 经过全连接后,维度变成[1,batch_size,5]
    38. out_put = self.fc(hn).squeeze(0) # 全连接层
    39. # 挤掉第0维度,返回[batch_size,5]的数据
    40. return out_put
    41. # 设计CNN网络
    42. class CNN(nn.Module):
    43. def __init__(self,len_feature,len_words,longest,typenum=5,weight=None,drop_out=0.5):
    44. super(CNN, self).__init__()
    45. self.len_feature = len_feature # d的大小
    46. self.len_words = len_words # 单词数目
    47. self.longest = longest # 最长句子单词数目
    48. self.dropout = nn.Dropout(drop_out) # dropout层
    49. if weight is None: # 随机初始化
    50. x = nn.init.xavier_normal(torch.Tensor(len_words,len_feature))
    51. self.embedding = nn.Embedding(num_embeddings=len_words,embedding_dim=len_feature,_weight=x)
    52. else: # Glove初始化
    53. self.embedding = nn.Embedding(num_embeddings=len_words,embedding_dim=len_feature,_weight=weight)
    54. # Conv2d参数详解:(输入通道数:1,输出通道数:l_l,卷积核大小:(行数,列数))
    55. # padding是指往句子两侧加 0,因为有的句子只有一个单词
    56. # 那么 X 就是 1*50 对 W=2*50 的卷积核根本无法进行卷积操作
    57. # 因此要在X两侧行加0(两侧列不加),(padding=(1,0))变成 3*50
    58. # 又比如 padding=(2,0)变成 5*50
    59. self.conv1 = nn.Sequential(nn.Conv2d(1,longest,(2,len_feature),padding=(1,0)),nn.ReLU()) # 序列,relu激活函数 第1个卷积核+激活层
    60. self.conv2 = nn.Sequential(nn.Conv2d(1,longest,(3,len_feature),padding=(1,0)),nn.ReLU()) # 第2个卷积核+激活层
    61. self.conv3 = nn.Sequential(nn.Conv2d(1,longest,(4,len_feature),padding=(2,0)),nn.ReLU()) # 第3个卷积核+激活层
    62. self.conv4 = nn.Sequential(nn.Conv2d(1,longest,(5,len_feature),padding=(2,0)),nn.ReLU()) # 第4个卷积核+激活层
    63. # 全连接层
    64. self.fc = nn.Linear(4 * longest,typenum)
    65. def forward(self,x):
    66. # x:数据,维度为[batch_size,句子长度]
    67. x = torch.LongTensor(x)
    68. # 通过词嵌入后,维度为[batch_size,1,句子长度,d]
    69. out_put = self.embedding(x).view(x.shape[0],1,x.shape[1],self.len_feature) # 词嵌入
    70. # dropout后不变,记为x
    71. out_put = self.dropout(out_put) # dropout层
    72. """X经过2*d卷积后,维度为[batch_size,l_l,句子长度+2-1,1]"""
    73. """挤掉第三维度(维度从0开始),[batch_size,l_l,句子长度+2-1]记为Y_1"""
    74. """注意:句子长度+2-1的2是padding造成的行数扩张"""
    75. conv1 = self.conv1(out_put).squeeze(3) # 第1个卷积
    76. """X经过3*d卷积后,维度为[batch_size,l_l,句子长度+2-2,1]"""
    77. """挤掉第三维度(维度从0开始),[batch_size,l_l,句子长度+2-2]记为Y_2"""
    78. conv2 = self.conv2(out_put).squeeze(3) # 第2个卷积
    79. """X经过4*d卷积后,维度为[batch_size,l_l,句子长度+4-3,1]"""
    80. """挤掉第三维度(维度从0开始),[batch_size,l_l,句子长度+4-3]记为Y_3"""
    81. conv3 = self.conv3(out_put).squeeze(3) # 第3个卷积
    82. """X经过5*d卷积后,维度为[batch_size,l_l,句子长度+4-4,1]"""
    83. """挤掉第三维度(维度从0开始),[batch_size,l_l,句子长度+4-4]记为Y_4"""
    84. conv4 = self.conv4(out_put).squeeze(3) # 第4个卷积
    85. """分别对(Y_1,Y_2,Y_3,Y_4)的第二维(维度从0开始)进行pooling"""
    86. """得到4个[batch_size,,l_l,1]的向量"""
    87. pool1 = F.max_pool1d(conv1, conv1.shape[2])
    88. pool2 = F.max_pool1d(conv2, conv2.shape[2])
    89. pool3 = F.max_pool1d(conv3, conv3.shape[2])
    90. pool4 = F.max_pool1d(conv4, conv4.shape[2])
    91. # 拼接得到[batch_size,l_l*4,1]的向量
    92. # 挤掉第二维(维度从0开始)为[batch_size,l_l*4]
    93. pool = torch.cat([pool1,pool2,pool3,pool4],1).squeeze(2) # 拼接起来
    94. # 经过全连接层后,维度为[batch_size,5]
    95. out_put = self.fc(pool)
    96. return out_put

    四、实验结果

     

    在准确率上,测试集上RNN的准确率比CNN都要高,且测试集的损失值也要比CNN低。比较随机初始化与Glove初始化,在相同的模型下,Glove初始化比随机初始化的效果要好,也就是在测试集上准确率高,损失值小。测试集的准确率在60%左右。

    通过上述的结果的显示并不能说明RNN在长句子情感分类方面的优势,因为RNN具有短期记忆,能够处理好词与词之间的关系,以下的结果是在长句子分类上两者的比较,是在测试集中单词数大于20的句子的损失值和正确率。

     可以看出,RNN的效果并不比CNN好,无论是CNN还是RNN,长句子的情感分类准确率也只有大概55%左右,比总体的平均正确率低了均10%。

    五、总结

    这个实验可以使用cuda加速,但是由于我的电脑没有所以就跑得比较慢,只需要在comparison_plot和Neural_network中的一些代码加入.cuda()和.cpu()即可,也可以将代码放入kaggle中用gpu跑或者使用google,我这边也遇到了麻烦所以也没能进行。

    在实际神经网络通常是输入一批样本然后得到输出,进行了一个padding操作,即补长,反正数据分batch失败,在实战中先把数据按照句子长度进行了排序,尽量使同一个batch句子长度一致,这样子可以避免零填充,同时设置padding的ID为0。

  • 相关阅读:
    sql 常用命令-----增删查改
    UVA 439 骑士的移动 Knight Moves
    域名解析DNS:如何查询txt类型的解析记录
    【算法】PTA刷题记录
    firewalld防火墙基础
    elementUI的table使用展开功能( type=“expand“ ),展开时合起上一次展开的内容,始终保持展开内容为一个,并且再次点击合起自身
    Linux配置成代理服务器
    蓝牙SDK状态机与车载音频HSM状态机比较
    【JSON2WEB】11 基于 Amis 角色功能权限设置页面
    Improving Transferability of Adversarial Examples with Input Diversity
  • 原文地址:https://blog.csdn.net/soobinnim/article/details/126187449