赞
踩
长短时记忆网络(Long Short Term Memory Network, LSTM),是一种改进之后的循环神经网络,可以解决RNN无法处理长距离的依赖的问题,目前比较流行。LSTM 通过三个“门”结构来控制不同时刻的状态和输出,分别为:遗忘门,输入门,输出门,结构图如下:
遗忘门(forget gate):它决定了上一时刻的单元状态c_t-1有多少保留到当前时刻c_t
输入门(input gate):它决定了当前时刻网络的输入x_t有多少保存到单元状态c_t
输出门(output gate):控制单元状态c_t有多少输出到 LSTM 的当前输出值h_t
import random import jieba import pandas as pd import numpy as np # 引入需要的模块 from keras.preprocessing.text import Tokenizer from keras.preprocessing.sequence import pad_sequences from keras.utils import to_categorical from keras.layers import Dense, Input, Flatten, Dropout from keras.layers import LSTM, Embedding, GRU from keras.models import Sequential # 整个过程包括:语料加载,分词和去停用词,数据预处理 # 使用 LSTM 分类,使用 GRU 分类 # 加载停用词 stopwords = pd.read_csv('./NB_SVM/stopwords.txt', index_col=False, quoting=3, sep="\t", names=['stopword'], encoding='utf-8') print("stopwords:\n", stopwords.head()) stopwords = stopwords['stopword'].values # 加载语料,语料是4个已经分好类的 csv 文件 laogong_df = pd.read_csv('./NB_SVM/beilaogongda.csv', encoding='utf-8', sep=',', index_col=[0]) laopo_df = pd.read_csv('./NB_SVM/beilaopoda.csv', encoding='utf-8', sep=',', index_col=[0]) erzi_df = pd.read_csv('./NB_SVM/beierzida.csv', encoding='utf-8', sep=',', index_col=[0]) nver_df = pd.read_csv('./NB_SVM/beinverda.csv', encoding='utf-8', sep=',', index_col=[0]) # 删除语料的nan行 laogong_df.dropna(inplace=True) laopo_df.dropna(inplace=True) erzi_df.dropna(inplace=True) nver_df.dropna(inplace=True) print("laogong_df:\n", laogong_df.head()) print("laopo_df:\n", laopo_df.head()) print("erzi_df:\n", erzi_df.head()) print("nver_df:\n", nver_df.head()) # 转换 laogong = laogong_df.segment.values.tolist() laopo = laopo_df.segment.values.tolist() erzi = erzi_df.segment.values.tolist() nver = nver_df.segment.values.tolist() # 定义分词和打标签函数preprocess_text # 参数content_lines即为上面转换的list # 参数sentences是定义的空list,用来储存打标签之后的数据 # 参数category 是类型标签 jieba.add_word("报警人") jieba.add_word("防护装备") jieba.add_word("防护设备") jieba.suggest_freq(("人", "称"), tune=True) def preprocess_text(content_lines, sentences, category): for line in content_lines: try: segs = jieba.lcut(line) segs = [v for v in segs if not str(v).isdigit()] # 去数字 segs = list(filter(lambda x: x.strip(), segs)) # 去左右空格 segs = list(filter(lambda x: len(x) > 1, segs)) # 长度为1的字符 segs = list(filter(lambda x: x not in stopwords, segs)) # 去掉停用词 sentences.append((" ".join(segs), category)) # 打标签 except Exception: print(line) continue # 调用函数、生成训练数据 sentences = [] preprocess_text(laogong, sentences,0) preprocess_text(laopo, sentences, 1) preprocess_text(erzi, sentences, 2) preprocess_text(nver, sentences, 3) # 打散数据,生成更可靠的训练集 random.shuffle(sentences) # 控制台输出前10条数据,观察一下 for sentence in sentences[:10]: print(sentence[0], sentence[1]) # 所有特征和对应标签 all_texts = [sentence[0] for sentence in sentences] all_labels = [sentence[1] for sentence in sentences] # 使用 LSTM 对数据进行分类 # 预定义变量 MAX_SEQUENCE_LENGTH = 100 # 最大序列长度 EMBEDDING_DIM = 200 # embdding 维度 VALIDATION_SPLIT = 0.16 # 验证集比例 TEST_SPLIT = 0.2 # 测试集比例 # keras的sequence模块文本序列填充 ''' Tokenizer是一个将文本向量化,转换成序列的类。用来文本处理的分词、嵌入 keras.preprocessing.text.Tokenizer(num_words=None, filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n', lower=True, split=' ', char_level=False, oov_token=None, document_count=0) 参数说明: num_words: 默认是None处理所有字词,但是如果设置成一个整数,那么最后返回的是最常见的、出现频率最高的num_words个字词。一共保留 num_words-1 个词。 filters: 过滤一些特殊字符,默认上文的写法就可以了。 lower: 是否全部转为小写。 split: 分词的分隔符字符串,默认为空格。因为英文分词分隔符就是空格。 char_level: 分字。 oov_token: if given, it will be added to word_index and used to replace out-of-vocabulary words during text_to_sequence calls 相关的类方法: 方法 参数 返回值 fit_on_texts(texts) texts:要用以训练的文本列表 - texts_to_sequences(texts) texts:待转为序列的文本列表 序列的列表,列表中每个序列对应于一段输入文本 属性: word_index: 字典,将单词(字符串)映射为它们的排名或者索引。仅在调用fit_on_texts之后设置。 ''' tokenizer = Tokenizer() tokenizer.fit_on_texts(all_texts) sequences = tokenizer.texts_to_sequences(all_texts) word_index = tokenizer.word_index print('Found %s unique tokens.' % len(word_index)) data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH) labels = to_categorical(np.asarray(all_labels)) print('Shape of data tensor:', data.shape) print('Shape of label tensor:', labels.shape) print("data:", data) print("labels:", labels) # 数据切分 p1 = int(len(data) * (1 - VALIDATION_SPLIT - TEST_SPLIT)) p2 = int(len(data) * (1 - TEST_SPLIT)) x_train = data[:p1] y_train = labels[:p1] x_val = data[p1:p2] y_val = labels[p1:p2] x_test = data[p2:] y_test = labels[p2:] # LSTM训练模型 model = Sequential() ''' 嵌入层Embedding将正整数(下标)转换为具有固定大小的向量,Embedding层只能作为模型的第一层 输入shape 形如(samples,sequence_length)的2D张量 输出shape 形如(samples, sequence_length, output_dim)的3D张量 参数 input_dim:大或等于0的整数,字典长度,即输入数据最大下标+1 output_dim:大于0的整数,代表全连接嵌入的维度 input_length:当输入序列的长度固定时,该值为其长度。如果要在该层后接Flatten层,然后接Dense层,则必须指定该参数,否则Dense层的输出维度无法自动推断。 ''' model.add(Embedding(len(word_index) + 1, EMBEDDING_DIM, input_length=MAX_SEQUENCE_LENGTH)) # recurrent_dropout是给递归状态 C 设置的Dropout参数 model.add(LSTM(200, dropout=0.2, recurrent_dropout=0.2)) model.add(Dropout(0.2)) model.add(Dense(64, activation='relu')) model.add(Dense(labels.shape[1], activation='softmax')) model.summary() # 模型编译 # 进一步优化损失函数在更新中存在摆动幅度过大的问题,并且进一步加快函数的收敛速度, # RMSProp算法对权重 W 和偏置 b 的梯度使用了微分平方加权平均数。 # 这种做法有利于消除了摆动幅度大的方向,用来修正摆动幅度,使得各个维度的摆动幅度都较小。另一方面也使得网络函数收敛更快。 model.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['acc']) # 训练 model.fit(x_train, y_train, validation_data=(x_val, y_val), epochs=9, batch_size=128) model.save('./lstm.h5') # 模型评估 # 属性model.metrics_names将提供显示标签 print("显示标签:", model.metrics_names) print(model.evaluate(x_test, y_test))
原文:
https://soyoger.blog.csdn.net/article/details/108729405
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。