创建数据读取器train_reader 和test_reader
定义网络
定义损失函数
定义优化算法
数据是以数据标签的方式表示一个句子。
所以每个句子都是以一串整数来表示的,每个数字都是对应一个单词。
数据集就会有一个数据集字典,这个字典是训练数据中出现单词对应的数字标签。
# 获取训练和预测数据 print("加载训练数据中...") train_reader = paddle.batch(paddle.reader.shuffle(imdb.train(word_dict), 512), batch_size=128) print("加载测试数据中...") test_reader = paddle.batch(imdb.test(word_dict), batch_size=128) print('完成') 加载训练数据中... 加载测试数据中... 完成 遗忘门:用来控制记忆消失程度。 输入门:决定了当前时刻的输入信息,有多少信息将添加到记忆信息流中,与遗忘门计算公式几乎一致,输入门同样通过一个激活函数来实现。 记忆状态:计算当前输入与过去的记忆所具有的信息总量。 输出门:控制着有多少记忆信息将被用于下一阶段的更新中。在防止梯度消失的问题上,LSTM效果比RNN要好, 随着任务难度的加深,文本序列长度的增加,模型后面一部分可能会丢失原始的信息,就出现了RNN的变体LSTM和GRU。
# 定义长短期记忆网络 def lstm_net(ipt, input_dim): # 以数据的IDs作为输入 emb = fluid.layers.embedding(input=ipt, size=[input_dim, 128], is_sparse=True) # 第一个全连接层 fc1 = fluid.layers.fc(input=emb, size=128) # 进行一个长短期记忆操作 lstm1, _ = fluid.layers.dynamic_lstm(input=fc1, #返回:隐藏状态(hidden state),LSTM的神经元状态 size=128) #size=4*hidden_size # 第一个最大序列池操作 fc2 = fluid.layers.sequence_pool(input=fc1, pool_type='max') # 第二个最大序列池操作 lstm2 = fluid.layers.sequence_pool(input=lstm1, pool_type='max') # 以softmax作为全连接的输出层,大小为2,也就是正负面 out = fluid.layers.fc(input=[fc2, lstm2], size=2, act='softmax')#二分类,1x2的概率分布 return out这里可以先定义一个输入层,这样要注意的是我们使用的数据属于序列数据,所以我们可以设置lod_level为1,当该参数不为0时,表示输入的数据为序列数据,默认lod_level的值是0.
# 定义输入数据, lod_level不为0指定输入数据为序列数据 words = fluid.layers.data(name='words', shape=[1], dtype='int64', lod_level=1) label = fluid.layers.data(name='label', shape=[1], dtype='int64')#label:正向或者负向 # 获取长短期记忆网络 model = lstm_net(words, dict_dim)接着定义损失函数,这里同样是一个分类任务,所以使用的损失函数也是交叉熵损失函数。这里也可以使用fluid.layers.accuracy()接口定义一个输出分类准确率的函数,可以方便在训练的时候,输出测试时的分类准确率,观察模型收敛的情况。
# 获取损失函数和准确率 cost = fluid.layers.cross_entropy(input=model, label=label) avg_cost = fluid.layers.mean(cost) acc = fluid.layers.accuracy(input=model, label=label) # 获取预测程序 test_program = fluid.default_main_program().clone(for_test=True)然后是定义优化方法,这里使用的时Adagrad优化方法,Adagrad优化方法多用于处理稀疏数据,设置学习率为0.002。
# 定义优化方法 optimizer = fluid.optimizer.AdagradOptimizer(learning_rate=0.002) opt = optimizer.minimize(avg_cost)如果读取有GPU环境,可以尝试使用GPU来训练,使用方式是使用fluid.CUDAPlace(0)来创建。
# 定义使用CPU还是GPU,使用CPU时use_cuda = False,使用GPU时use_cuda = True use_cuda = True place = fluid.CUDAPlace(0) if use_cuda else fluid.CPUPlace() exe = fluid.Executor(place) # 进行参数初始化 exe.run(fluid.default_startup_program()) []定义数据数据的维度,数据的顺序是一条句子数据对应一个标签。
# 定义输入数据的维度 # 定义数据数据的维度,数据的顺序是一条句子数据对应一个标签 feeder = fluid.DataFeeder(place=place, feed_list=[words, label])现在就可以开始训练了,这里设置训练的循环是2次,大家可以根据情况设置更多的训练轮数。我们在训练中,每40个Batch打印一层训练信息和进行一次测试,测试是使用测试集进行预测并输出损失值和准确率,测试完成之后,对之前预测的结果进行求平均值。
# 开始训练 for pass_id in range(10): # 进行训练 train_cost = 0 for batch_id, data in enumerate(train_reader()): #遍历train_reader迭代器 train_cost = exe.run(program=fluid.default_main_program(),#运行主程序 feed=feeder.feed(data), #喂入一个batch的数据 fetch_list=[avg_cost]) #fetch均方误差 if batch_id % 40 == 0: #每40次batch打印一次训练、进行一次测试 print('Pass:%d, Batch:%d, Cost:%0.5f' % (pass_id, batch_id, train_cost[0])) # 进行测试 test_costs = [] #测试的损失值 test_accs = [] #测试的准确率 for batch_id, data in enumerate(test_reader()): test_cost, test_acc = exe.run(program=test_program, feed=feeder.feed(data), fetch_list=[avg_cost, acc]) test_costs.append(test_cost[0]) test_accs.append(test_acc[0]) # 计算平均预测损失在和准确率 test_cost = (sum(test_costs) / len(test_costs)) test_acc = (sum(test_accs) / len(test_accs)) print('Test:%d, Cost:%0.5f, ACC:%0.5f' % (pass_id, test_cost, test_acc)) #保存模型 model_save_dir = "/home/aistudio/work/emotionclassify.inference.model" # 如果保存路径不存在就创建 if not os.path.exists(model_save_dir): os.makedirs(model_save_dir) print ('save models to %s' % (model_save_dir)) fluid.io.save_inference_model(model_save_dir, #保存推理model的路径 ['words'], #推理(inference)需要 feed 的数据 [model], #保存推理(inference)结果的 Variables exe) #exe 保存 inference model Pass:0, Batch:0, Cost:0.73125 Pass:0, Batch:40, Cost:0.06795 Pass:0, Batch:80, Cost:0.00722 Pass:0, Batch:120, Cost:0.80844 Pass:0, Batch:160, Cost:0.22205 Test:0, Cost:1.12195, ACC:0.50171 Pass:1, Batch:0, Cost:2.13347 Pass:1, Batch:40, Cost:0.48804 Pass:1, Batch:80, Cost:0.21535 Pass:1, Batch:120, Cost:0.81571 Pass:1, Batch:160, Cost:0.33186 Test:1, Cost:0.83362, ACC:0.50191 Pass:2, Batch:0, Cost:1.40742 Pass:2, Batch:40, Cost:0.55047 Pass:2, Batch:80, Cost:0.27269 Pass:2, Batch:120, Cost:0.74456 Pass:2, Batch:160, Cost:0.35957 Test:2, Cost:0.71608, ACC:0.50769 Pass:3, Batch:0, Cost:1.12344 Pass:3, Batch:40, Cost:0.55675 Pass:3, Batch:80, Cost:0.30137 Pass:3, Batch:120, Cost:0.67230 Pass:3, Batch:160, Cost:0.35690 Test:3, Cost:0.63739, ACC:0.54560 Pass:4, Batch:0, Cost:0.98897 Pass:4, Batch:40, Cost:0.55052 Pass:4, Batch:80, Cost:0.29672 Pass:4, Batch:120, Cost:0.59823 Pass:4, Batch:160, Cost:0.35738 Test:4, Cost:0.57975, ACC:0.61902 Pass:5, Batch:0, Cost:0.80312 Pass:5, Batch:40, Cost:0.50581 Pass:5, Batch:80, Cost:0.27092 Pass:5, Batch:120, Cost:0.55160 Pass:5, Batch:160, Cost:0.32211 Test:5, Cost:0.53265, ACC:0.69416 Pass:6, Batch:0, Cost:0.70552 Pass:6, Batch:40, Cost:0.49984 Pass:6, Batch:80, Cost:0.27171 Pass:6, Batch:120, Cost:0.52073 Pass:6, Batch:160, Cost:0.31178 Test:6, Cost:0.49651, ACC:0.74736 Pass:7, Batch:0, Cost:0.69794 Pass:7, Batch:40, Cost:0.50185 Pass:7, Batch:80, Cost:0.27300 Pass:7, Batch:120, Cost:0.46273 Pass:7, Batch:160, Cost:0.35845 Test:7, Cost:0.46813, ACC:0.78116 Pass:8, Batch:0, Cost:0.61882 Pass:8, Batch:40, Cost:0.45831 Pass:8, Batch:80, Cost:0.27965 Pass:8, Batch:120, Cost:0.44373 Pass:8, Batch:160, Cost:0.30215 Test:8, Cost:0.44874, ACC:0.80029 Pass:9, Batch:0, Cost:0.60523 Pass:9, Batch:40, Cost:0.47129 Pass:9, Batch:80, Cost:0.22142 Pass:9, Batch:120, Cost:0.39324 Pass:9, Batch:160, Cost:0.26854 Test:9, Cost:0.43634, ACC:0.80823 save models to /home/aistudio/work/emotionclassify.inference.model ['save_infer_model/scale_0']我们先定义三个句子,第一句是中性的,第二句偏向正面,第三句偏向负面。然后把这些句子读取到一个列表中。
# 定义预测数据 reviews_str = ['read the book forget the movie', 'this is a great movie', 'this is very bad']#第一句是中性,第二句是正向,第三局是负向 # 把每个句子拆成一个个单词 reviews = [c.split() for c in reviews_str]然后把句子转换成编码,根据数据集的字典,把句子中的单词转换成对应标签。
# 获取结束符号的标签 UNK = word_dict['<unk>'] # 获取每句话对应的标签 lod = [] for c in reviews: # 需要把单词进行字符串编码转换 lod.append([word_dict.get(words.encode('utf-8'), UNK) for words in c])获取输入数据的维度和大小。
# 获取每句话的单词数量 base_shape = [[len(c) for c in lod]]将要预测的数据转换成张量,准备开始预测。
# 生成预测数据 tensor_words = fluid.create_lod_tensor(lod, base_shape, place) infer_exe = fluid.Executor(place) #创建推测用的executor inference_scope = fluid.core.Scope() #Scope指定作用域 with fluid.scope_guard(inference_scope):#修改全局/默认作用域(scope), 运行时中的所有变量都将分配给新的scope。 #从指定目录中加载 推理model(inference model) [inference_program, #推理的program feed_target_names, #str列表,包含需要在推理program中提供数据的变量名称 fetch_targets] = fluid.io.load_inference_model(model_save_dir,#fetch_targets: 推断结果,model_save_dir:模型训练路径 infer_exe) #infer_exe: 运行 inference model的 executor results = infer_exe.run(inference_program, #运行预测程序 feed={feed_target_names[0]: tensor_words},#喂入要预测的x值 fetch_list=fetch_targets) #得到推测结果 # 打印每句话的正负面概率 for i, r in enumerate(results[0]): print("\'%s\'的预测结果为:正面概率为:%0.5f,负面概率为:%0.5f" % (reviews_str[i], r[0], r[1])) 'read the book forget the movie'的预测结果为:正面概率为:0.54671,负面概率为:0.45329 'this is a great movie'的预测结果为:正面概率为:0.62144,负面概率为:0.37856 'this is very bad'的预测结果为:正面概率为:0.37344,负面概率为:0.62656预测结果显示这个模型的预测较为准确,输出结果符合人类观察的预期;可以继续调整网络参数、结构,使其能够更好的对文本进行情感分类。