Python 智能项目:6~10(1)https://developer.aliyun.com/article/1426935
训练 RBM
此处说明的_train
函数可用于训练 RBM。 在此函数中,我们首先调用_network
函数以构建 RBM 网络结构,然后在激活的 TensorFlow 会话中针对指定周期数训练模型。 使用 TensorFlow 的saver
函数以指定的时间间隔保存模型:
def _train(self): self.__network() # TensorFlow graph execution with tf.Session() as sess: self.saver = tf.train.Saver() #saver = tf.train.Saver(write_version=tf.train.SaverDef.V2) # Initialize the variables of the Model init = tf.global_variables_initializer() sess.run(init) total_batches = self.train_data.shape[0]//self.batch_size batch_gen = self.next_batch() # Start the training for epoch in range(self.epochs): if epoch < 150: self.k = 2 if (epoch > 150) & (epoch < 250): self.k = 3 if (epoch > 250) & (epoch < 350): self.k = 5 if (epoch > 350) & (epoch < 500): self.k = 9 # Loop over all batches for i in range(total_batches): self.X_train = next(batch_gen) # Run the weight update #batch_xs = (batch_xs > 0)*1 _ = sess.run([self.updt],feed_dict={self.x:self.X_train}) # Display the running step if epoch % self.display_step == 0: print("Epoch:", '%04d' % (epoch+1)) print(self.outdir) self.saver.save(sess,os.path.join(self.outdir,'model'), global_step=epoch) # Do the prediction for all users all items irrespective of whether they have been rated self.logits_pred = tf.reshape(self.x_, [self.users,self.num_movies,self.num_ranks]) self.probs = tf.nn.softmax(self.logits_pred,axis=2) out = sess.run(self.probs,feed_dict={self.x:self.train_data}) recs = [] for i in range(self.users): for j in range(self.num_movies): rec = [i,j,np.argmax(out[i,j,:]) +1] recs.append(rec) recs = np.array(recs) df_pred = pd.DataFrame(recs,columns= ['userid','movieid','predicted_rating']) df_pred.to_csv(self.outdir + 'pred_all_recs.csv',index=False) print("RBM training Completed !")
在前面的函数中要强调的重要一点是使用自定义next_batch
函数创建随机批量。 该函数在下面的代码片段中定义,并且用于定义迭代器batch_gen
,该迭代器可以由next
方法调用以检索下一个小批量:
def next_batch(self): while True: ix = np.random.choice(np.arange(self.data.shape[0]),self.batch_size) train_X = self.data[ix,:,:] yield train_X
需要注意的一件事是,在训练结束时,我们会预测所有用户对所有电影的收视率,无论它们是否被评级。 具有最高可能性的评级,将从五个可能的评级(即从 1 到 5)中给出最终评级。 由于在 Python 中,索引从零开始,因此在使用argmax
获得最高概率的位置之后,我们加一以获得实际评分。 因此,在训练结束时,我们有一个pred_all_recs.csv
文件,其中包含所有训练和测试记录的预测评分。 请注意,测试记录已嵌入训练记录中,并且评分的所有索引(从 1 到 5)都设置为零。
但是,一旦我们从用户观看过的电影的隐藏表示中充分训练了模型,就可以学习从用户未看过的电影中生成评分。
可以通过调用以下命令来训练模型:
python rbm.py main_process --mode train --train_file '/home/santanu/ML_DS_Catalog-/Collaborating Filtering/ml-100k/train_data.npy' --outdir '/home/santanu/ML_DS_Catalog-/Collaborating Filtering/' --num_hidden 5 --epochs 1000
从日志中可以看到,仅使用5
隐藏层训练1000
周期的模型大约需要52
秒。
RBM training Completed ! 52.012 s: process RBM
请注意,受限玻尔兹曼机网络已在配备 GeForce Zotac 1070 GPU 和 64 GB RAM 的 Ubuntu 机器上进行了训练。 训练时间可能会根据用于训练网络的系统而有所不同。
将训练后的 RBM 用于推理
鉴于我们已经在训练过程中生成了带有所有预测的文件pred_all_recs.csv
,因此针对 RBM 的推理非常简单。 我们要做的只是基于提供的测试文件从pred_all_recs.csv
中提取测试记录。 另外,我们通过将1
添加到它们的当前值来求助于原始的userid
和movieid
。 返回原始 ID 的目的是能够从u.user
和u.item
文件中添加用户和电影信息。
推理块如下:
def inference(self): self.df_result = self.test_df.merge(self.train_df,on=['userid','movieid']) # in order to get the original ids we just need to add 1 self.df_result['userid'] = self.df_result['userid'] + 1 self.df_result['movieid'] = self.df_result['movieid'] + 1 if self.user_info_file != None: self.df_result.merge(self.user_info_df,on=['userid']) if self.movie_info_file != None: self.df_result.merge(self.movie_info_df,on=['movieid']) self.df_result.to_csv(self.outdir + 'test_results.csv',index=False) print(f'output written to {self.outdir}test_results.csv') test_rmse = (np.mean((self.df_result['rating'].values - self.df_result['predicted_rating'].values)**2))**0.5 print(f'test RMSE : {test_rmse}')
可以按以下方式调用推断:
python rbm.py main_process --mode test --train_file '/home/santanu/ML_DS_Catalog-/Collaborating Filtering/pred_all_recs.csv' --test_file '/home/santanu/ML_DS_Catalog-/Collaborating Filtering/ml-100k/test_data.npy' --outdir '/home/santanu/ML_DS_Catalog-/Collaborating Filtering/' --user_info_file '/home/santanu/ML_DS_Catalog-/Collaborating Filtering/ml-100k/u.user' --movie_info_file '/home/santanu/ML_DS_Catalog-/Collaborating Filtering/ml-100k/u.item'
通过在 RBM 中仅使用5
隐藏单元,我们获得了大约1.19
的测试均方根误差(RMSE),这是值得称赞的,因为我们选择了这样一个简单的网络。 以下代码块中提供了推理的输出日志,以供参考:
output written to /home/santanu/ML_DS_Catalog-/Collaborating Filtering/test_results.csv test RMSE : 1.1999306704742303 458.058 ms: process RBM
我们从test_results.csv
观察userid 1
的推断结果,如下所示(请参见“图 6.9”):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U3bkhohX-1681654125434)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-proj-py/img/99f2041e-3c09-4503-b01b-c15bcdd1f6b3.png)]
图 6.9:用户 ID 1 的保留数据验证结果
从前面的屏幕快照(“图 6.9”)中的预测可以看出,RBM 在预测userid
1
的电影的保留集方面做得很好。
建议您将最终收视率预测作为对每个电影收视率预测的多项式概率分布的收视率的期望值,并与采用最高收视率的方法进行比较,了解多项式分布的概率的效果如何。 可以在这个页面上找到用于协同过滤的 RBM 论文。受限玻尔兹曼机有关的代码位于这里。
总结
阅读完本章后,您现在应该能够使用受限玻尔兹曼机构建智能推荐系统,并根据您的领域和要求以有趣的方式对其进行扩展。 有关本章中说明的项目的详细实现,请参考此项目的 GiHub 链接。
在下一章中,我们将处理移动应用的创建,以执行电影评论的情感分析。 我期待您的参与。
七、电影评论情感分析移动应用
在这个现代时代,将数据发送到云中基于 AI 的应用进行推理是司空见惯的。 例如,用户可以将手机拍摄的图像发送到 Amazon Rekognition API,该服务可以标记图像中存在的各种对象,人物,文本,场景等。 利用托管在云中的基于 AI 的应用的服务的优势在于其易用性。 移动应用只需要向基于 AI 的服务以及图像发出 HTTPS 请求,然后在几秒钟内,该服务将提供推理结果。 这些机器学习即服务供应商中的一些如下:
- 亚马逊 Rekognition
- 亚马逊 Polly
- 亚马逊 Lex
- Microsoft Azure 认知服务
- IBM Watson
- Google Cloud Vision
下图“图 7.1,”说明了这种应用在云上托管时的架构以及如何与移动设备交互:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dTosL9Fx-1681654125435)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-proj-py/img/71528e0e-5829-47db-a724-312dc884f6f7.png)]
图 7.1:移动应用与托管在云上的 AI 模型进行通信
如您在上图中所见,移动应用将图像本地化和分类请求与图像一起发送到托管在云上的模型,并且在对提供的图像进行推断之后,模型将结果发送回去。 在云上使用此类服务的优势如下:
- 无需收集数据来训练这种模型
- 将 AI 模型作为服务托管不会带来任何痛苦
- 无需担心重新训练模型
所有上述内容将由服务提供商负责。 但是,在云上使用这种 AI 应用确实也有一些缺点,其中包括:
- 用户无法在移动设备上本地运行推理。 所有推理都需要通过向托管 AI 应用的服务器发送网络请求来完成。 如果没有网络连接,该移动应用将无法运行。 同样,通过网络从模型中获取预测可能会有一些延迟。
- 如果不是免费托管的云应用,则用户通常需要为运行的推理次数付费。
- 云托管的模型非常通用,用户无法控制使用自己的数据训练这些模型。 如果数据是唯一的,则在通用数据上经过训练的这种应用可能不会提供很好的结果。
可以通过在移动设备本身上运行推理,而不是通过互联网将数据发送到 AI 应用来克服部署在云上的 AI 应用的上述缺点。
可以使用特定于移动应用所针对问题的训练数据在具有适当 CPU 和 GPU 的任何系统上训练该模型。 然后,可以将经过训练的模型转换为优化的文件格式,而只需要运行推理所需的权重和操作即可。 然后,可以将优化的模型与移动应用集成,并且可以将整个项目作为应用加载到移动设备上。 训练后的模型的优化文件应尽可能轻巧,因为模型将与其他移动应用代码一起存储在移动设备上。 在本章中,我们将使用 TensorFlow mobile 开发一个 Android 移动应用。
技术要求
您需要具备 Python 3,TensorFlow 和 Java
的基本知识。
使用 TensorFlow Mobile 构建 Android 移动应用
在这个项目中,我们将使用 TensorFlow 的移动功能来优化训练好的模型作为协议缓冲区对象。 然后,我们将模型与 Android 应用集成,该应用的逻辑将用 Java 编写。 我们需要执行以下步骤:
- 在 TensorFlow 中构建模型并使用相关数据进行训练。
- 模型在验证数据集上令人满意地执行后,将 TensorFlow 模型转换为优化的 protobuf 对象(例如,
optimized_model.pb
)。 - 下载 Android Studio 及其先决条件。 用 Java 开发核心应用逻辑,并使用 XML 开发接口页面。
- 将 TensorFlow 训练有素的模型 protobuf 对象及其相关的依赖项集成到项目内的 Assets 文件夹中。
- 生成项目并运行它。
下图说明了此 Android 应用的实现(“图 7.2”):
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XH1HVHKv-1681654125435)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-proj-py/img/28904c06-b8aa-49ab-be57-95d06788ef97.png)]
图 7.2:移动应用部署架构图
Android 应用中的电影评论评分
我们将构建一个 Android 应用,该应用将基于电影评论的情感分析,将电影评论作为输入,并提供从0
到5
的等级作为输出。 首先将训练循环神经网络的 LSTM 版本,以对电影的情感进行二分类。 训练数据将由基于文本的电影评论以及0
或1
的二进制标签组成。 标签1
代表评论带有正面情绪,而0
则代表电影带有负面情绪。 从模型中,我们将预测情绪为正的可能性,然后将可能性放大五倍,以将其转换为合理的等级。 将使用 TensorFlow 构建模型,然后将训练后的模型转换为优化的冻结 protobuf 对象,以与 Android 应用逻辑集成。 冻结对象的大小将比原始训练模型小得多,并且仅用于推理目的。
我们将使用以下论文中标题为《学习单词向量进行情感分析》的可用数据集:
@InProceedings{maas-EtAl:2011:ACL-HLT2011, author = {Maas, Andrew L. and Daly, Raymond E. and Pham, Peter T. and Huang, Dan and Ng, Andrew Y. and Potts, Christopher}, title = {Learning Word Vectors for Sentiment Analysis}, booktitle = {Proceedings of the 49th Annual Meeting of the Association for Computational Linguistics: Human Language Technologies}, month = {June}, year = {2011}, address = {Portland, Oregon, USA}, publisher = {Association for Computational Linguistics}, pages = {142--150}, url = {http://www.aclweb.org/anthology/P11-1015} }
预处理电影评论文本
电影评论文本需要进行预处理,并转换为数字标记,与语料库中的不同单词相对应。 通过使用第一个50000
常见单词,Keras 分词器将这些单词转换为数字索引或标记。 我们已限制电影评论最多包含1000
个单词标记。 如果电影评论的单词标记少于1000
,则该评论的开头会填充零。 预处理之后,数据将分为训练,验证和测试集。 保存 Keras Tokenizer
对象以在推理期间使用。
用于预处理电影评论的详细代码(preprocess.py
)如下:
# -*- coding: utf-8 -*- """ Created on Sun Jun 17 22:36:00 2018 @author: santanu """ import numpy as np import pandas as pd import os import re from keras.preprocessing.text import Tokenizer from keras.preprocessing.sequence import pad_sequences import pickle import fire from elapsedtimer import ElapsedTimer # Function to clean the text and convert it into lower case def text_clean(text): letters = re.sub("[^a-zA-z0-9\s]", " ",text) words = letters.lower().split() text = " ".join(words) return text def process_train(path): review_dest = [] reviews = [] train_review_files_pos = os.listdir(path + 'train/pos/') review_dest.append(path + 'train/pos/') train_review_files_neg = os.listdir(path + 'train/neg/') review_dest.append(path + 'train/neg/') test_review_files_pos = os.listdir(path + 'test/pos/') review_dest.append(path + 'test/pos/') test_review_files_neg = os.listdir(path + 'test/neg/') review_dest.append(path + 'test/neg/') sentiment_label = [1]*len(train_review_files_pos) + \ [0]*len(train_review_files_neg) + \ [1]*len(test_review_files_pos) + \ [0]*len(test_review_files_neg) review_train_test = ['train']*len(train_review_files_pos) + \ ['train']*len(train_review_files_neg) + \ ['test']*len(test_review_files_pos) + \ ['test']*len(test_review_files_neg) reviews_count = 0 for dest in review_dest: files = os.listdir(dest) for f in files: fl = open(dest + f,'r') review = fl.readlines() review_clean = text_clean(review[0]) reviews.append(review_clean) reviews_count +=1 df = pd.DataFrame() df['Train_test_ind'] = review_train_test df['review'] = reviews df['sentiment_label'] = sentiment_label df.to_csv(path + 'processed_file.csv',index=False) print ('records_processed',reviews_count) return df def process_main(path): df = process_train(path) # We will tokenize the text for the most common 50000 words. max_fatures = 50000 tokenizer = Tokenizer(num_words=max_fatures, split=' ') tokenizer.fit_on_texts(df['review'].values) X = tokenizer.texts_to_sequences(df['review'].values) X_ = [] for x in X: x = x[:1000] X_.append(x) X_ = pad_sequences(X_) y = df['sentiment_label'].values index = list(range(X_.shape[0])) np.random.shuffle(index) train_record_count = int(len(index)*0.7) validation_record_count = int(len(index)*0.15) train_indices = index[:train_record_count] validation_indices = index[train_record_count:train_record_count + validation_record_count] test_indices = index[train_record_count + validation_record_count:] X_train,y_train = X_[train_indices],y[train_indices] X_val,y_val = X_[validation_indices],y[validation_indices] X_test,y_test = X_[test_indices],y[test_indices] np.save(path + 'X_train',X_train) np.save(path + 'y_train',y_train) np.save(path + 'X_val',X_val) np.save(path + 'y_val',y_val) np.save(path + 'X_test',X_test) np.save(path + 'y_test',y_test) # saving the tokenizer oject for inference with open(path + 'tokenizer.pickle', 'wb') as handle: pickle.dump(tokenizer, handle, protocol=pickle.HIGHEST_PROTOCOL) if __name__ == '__main__': with ElapsedTimer('Process'): fire.Fire(process_main)
代码preprocess.py
可以按以下方式调用:
python preprocess.py --path /home/santanu/Downloads/Mobile_App/aclImdb/
相同的输出日志如下:
Using TensorFlow backend. records_processed 50000 24.949 s: Process
建立模型
我们将构建一个简单的 LSTM 版本的循环神经网络,在输入层之后有一个嵌入层。 使用预训练的大小为 100 的 Glove 向量初始化嵌入层字向量,并将该层定义为trainable
,以便字向量嵌入可以根据训练数据进行更新。 隐藏状态和单元状态的维数也保持为100
。 使用二进制交叉熵损失训练模型。 为避免过拟合,将脊正则化添加到损失函数中。 Adam 优化器用于训练模型。
以下代码段显示了用于在 TensorFlow 中构建模型的函数:
def _build_model(self): with tf.variable_scope('inputs'): self.X = tf.placeholder(shape=[None, self.sentence_length],dtype=tf.int32,name="X") print (self.X) self.y = tf.placeholder(shape=[None,1], dtype=tf.float32,name="y") self.emd_placeholder = tf.placeholder(tf.float32,shape=[self.n_words,self.embedding_dim]) with tf.variable_scope('embedding'): # create embedding variable self.emb_W =tf.get_variable('word_embeddings',[self.n_words, self.embedding_dim],initializer=tf.random_uniform_initializer(-1, 1, 0),trainable=True,dtype=tf.float32) self.assign_ops = tf.assign(self.emb_W,self.emd_placeholder) # do embedding lookup self.embedding_input = tf.nn.embedding_lookup(self.emb_W,self.X,"embedding_input") print( self.embedding_input ) self.embedding_input = tf.unstack(self.embedding_input,self.sentence_length,1) #rint( self.embedding_input) # define the LSTM cell with tf.variable_scope('LSTM_cell'): self.cell = tf.nn.rnn_cell.BasicLSTMCell(self.hidden_states) # define the LSTM operation with tf.variable_scope('ops'): self.output, self.state = tf.nn.static_rnn(self.cell,self.embedding_input,dtype=tf.float32) with tf.variable_scope('classifier'): self.w = tf.get_variable(name="W", shape=[self.hidden_states,1],dtype=tf.float32) self.b = tf.get_variable(name="b", shape=[1], dtype=tf.float32) self.l2_loss = tf.nn.l2_loss(self.w,name="l2_loss") self.scores = tf.nn.xw_plus_b(self.output[-1],self.w,self.b,name="logits") self.prediction_probability = tf.nn.sigmoid(self.scores,name='positive_sentiment_probability') print (self.prediction_probability) self.predictions = tf.round(self.prediction_probability,name='final_prediction') self.losses = tf.nn.sigmoid_cross_entropy_with_logits(logits=self.scores,labels=self.y) self.loss = tf.reduce_mean(self.losses) + self.lambda1*self.l2_loss tf.summary.scalar('loss', self.loss) self.optimizer = tf.train.AdamOptimizer(self.learning_rate).minimize(self.losses) self.correct_predictions = tf.equal(self.predictions,tf.round(self.y)) print (self.correct_predictions) self.accuracy = tf.reduce_mean(tf.cast(self.correct_predictions, "float"), name="accuracy") tf.summary.scalar('accuracy', self.accuracy)
训练模型
在本部分中,我们将说明用于训练模型的 TensorFlow 代码。 训练模型时要适度10 epochs
,以避免过拟合。 用于优化器的学习率为0.001
,而训练批量大小和验证批量大小分别设置为250
和50
。 需要注意的一件事是,我们使用tf.train.write_graph
函数将模型图定义保存在model.pbtxt
文件中。 同样,一旦模型被训练,我们将使用tf.train.Saver
函数将模型权重保存在检查点文件model_ckpt
中。 model.pbtxt
和model_ckpt
文件将用于创建 protobuf 格式的 TensorFlow 模型的优化版本,该版本可以与 Android 应用集成:
def _train(self): self.num_batches = int(self.X_train.shape[0]//self.batch_size) self._build_model() self.saver = tf.train.Saver() with tf.Session() as sess: init = tf.global_variables_initializer() sess.run(init) sess.run(self.assign_ops,feed_dict={self.emd_placeholder:self.embedding_matrix}) tf.train.write_graph(sess.graph_def, self.path, 'model.pbtxt') print (self.batch_size,self.batch_size_val) for epoch in range(self.epochs): gen_batch = self.batch_gen(self.X_train,self.y_train,self.batch_size) gen_batch_val = self.batch_gen(self.X_val,self.y_val,self.batch_size_val) for batch in range(self.num_batches): X_batch,y_batch = next(gen_batch) X_batch_val,y_batch_val = next(gen_batch_val) sess.run(self.optimizer,feed_dict={self.X:X_batch,self.y:y_batch}) c,a = sess.run([self.loss,self.accuracy],feed_dict={self.X:X_batch,self.y:y_batch}) print(" Epoch=",epoch," Batch=",batch," Training Loss: ","{:.9f}".format(c), " Training Accuracy=", "{:.9f}".format(a)) c1,a1 = sess.run([self.loss,self.accuracy],feed_dict={self.X:X_batch_val,self.y:y_batch_val}) print(" Epoch=",epoch," Validation Loss: ","{:.9f}".format(c1), " Validation Accuracy=", "{:.9f}".format(a1)) results = sess.run(self.prediction_probability,feed_dict={self.X:X_batch_val}) print(results) if epoch % self.checkpoint_step == 0: self.saver.save(sess, os.path.join(self.path,'model'), global_step=epoch) self.saver.save(sess,self.path + 'model_ckpt') results = sess.run(self.prediction_probability,feed_dict={self.X:X_batch_val}) print(results)
批量生成器
在train
函数中,我们将使用批量生成器根据传递的批量大小生成随机批量。 生成器函数可以定义如下。 请注意,这些函数使用yield
代替return
。 通过使用所需参数调用函数,将创建批量的迭代器对象。 可以通过将next
方法应用于迭代器对象来检索批量。 我们将在每个周期开始时调用生成器函数,以便在每个周期中批量都是随机的。
以下代码段说明了用于生成批量迭代器对象的函数:
def batch_gen(self,X,y,batch_size): index = list(range(X.shape[0])) np.random.shuffle(index) batches = int(X.shape[0]//batch_size) for b in range(batches): X_train,y_train = X[index[b*batch_size: (b+1)*batch_size],:], y[index[b*batch_size: (b+1)*batch_size]] yield X_train,y_train
脚本**movie_review_model_train.py**
中提供了模型训练活动的详细代码。 可以通过以下方式调用相同的训练:
python movie_review_model_train.py process_main --path /home/santanu/Downloads/Mobile_App/ --epochs 10
训练的输出如下:
Using TensorFlow backend. (35000, 1000) (35000, 1) (7500, 1000) (7500, 1) (7500, 1000) (7500, 1) no of positive class in train: 17497 no of positive class in test: 3735 Tensor("inputs/X:0", shape=(?, 1000), dtype=int32) Tensor("embedding/embedding_lookup:0", shape=(?, 1000, 100), dtype=float32) Tensor("positive_sentiment_probability:0", shape=(?, 1), dtype=float32) ..... 25.043 min: Model train
将模型冻结为 protobuf 格式
以model.pbtxt
和model_ckpt
文件的形式保存,训练好的模型不能直接由 Android 应用使用。 我们需要将其转换为优化的 protobuf 格式(.pb
扩展文件),该格式可以与 Android 应用集成。 经过优化的 protobuf 格式的文件大小将比model.pbtxt
和model_ckpt
文件的总大小小得多。
以下代码(freeze_code.py
)将根据model.pbtxt
和model_ckpt
文件创建优化的 protobuf 模型:
# -*- coding: utf-8 -*- import sys import tensorflow as tf from tensorflow.python.tools import freeze_graph from tensorflow.python.tools import optimize_for_inference_lib import fire from elapsedtimer import ElapsedTimer #path = '/home/santanu/Downloads/Mobile_App/' #MODEL_NAME = 'model' def model_freeze(path,MODEL_NAME='model'): # Freeze the graph input_graph_path = path + MODEL_NAME+'.pbtxt' checkpoint_path = path + 'model_ckpt' input_saver_def_path = "" input_binary = False output_node_names = 'positive_sentiment_probability' restore_op_name = "save/restore_all" filename_tensor_name = "save/Const:0" output_frozen_graph_name = path + 'frozen_'+MODEL_NAME+'.pb' output_optimized_graph_name = path + 'optimized_'+MODEL_NAME+'.pb' clear_devices = True freeze_graph.freeze_graph(input_graph_path, input_saver_def_path, input_binary, checkpoint_path, output_node_names, restore_op_name, filename_tensor_name, output_frozen_graph_name, clear_devices, "") input_graph_def = tf.GraphDef() with tf.gfile.Open(output_frozen_graph_name, "rb") as f: data = f.read() input_graph_def.ParseFromString(data) output_graph_def = optimize_for_inference_lib.optimize_for_inference( input_graph_def, ["inputs/X" ],#an array of the input node(s) ["positive_sentiment_probability"], tf.int32.as_datatype_enum # an array of output nodes ) # Save the optimized graph f = tf.gfile.FastGFile(output_optimized_graph_name, "w") f.write(output_graph_def.SerializeToString()) if __name__ == '__main__': with ElapsedTimer('Model Freeze'): fire.Fire(model_freeze)
正如您在前面的代码中看到的那样,我们首先通过引用在声明模型时定义的名称来声明输入张量和输出张量。 使用输入和输出张量以及model.pbtxt
和model_ckpt
文件,通过使用来自tensorflow.python.tools
的freeze_graph
函数冻结模型。 下一步,使用tensorflow.python.tools
中的optimize_for_inference_lib
函数创建名为optimized_model.pb
的原型泡沫模型,进一步优化了冻结模型。 经过优化的 protobuf 模型optimized_model.pb
将与 Android 应用集成,以进行推理。
可以调用freeze_code.py
模型来创建 protobuf 格式文件,如下所示:
python freeze_code.py --path /home/santanu/Downloads/Mobile_App/ --MODEL_NAME model
前面命令的执行输出如下:
39.623 s: Model Freeze
创建用于推理的单词到标记的词典
在预处理过程中,我们训练了 Keras 标记器,用其数字单词索引替换单词,以便将处理后的电影评论输入 LSTM 模型进行训练。 我们还保留了具有最高单词频率的前50000
个单词,并将查看序列设置为1000
的最大长度。 尽管训练有素的 Keras 标记生成器已保存用于推断,但 Android 应用无法直接使用它。 我们可以还原 Keras 标记器,并将前50000
个单词及其对应的单词索引保存在文本文件中。 可以在 Android 应用中使用此文本文件,以构建词对索引词典,以将评论文本的词转换为其词索引。 重要的是要注意,可以通过参考tokenizer.word_index.
从加载的 Keras 标记生成器对象中检索单词到索引的映射,执行此活动tokenizer_2_txt.py
的详细代码如下:
import keras import pickle import fire from elapsedtimer import ElapsedTimer #path = '/home/santanu/Downloads/Mobile_App/aclImdb/tokenizer.pickle' #path_out = '/home/santanu/Downloads/Mobile_App/word_ind.txt' def tokenize(path,path_out): with open(path, 'rb') as handle: tokenizer = pickle.load(handle) dict_ = tokenizer.word_index keys = list(dict_.keys())[:50000] values = list(dict_.values())[:50000] total_words = len(keys) f = open(path_out,'w') for i in range(total_words): line = str(keys[i]) + ',' + str(values[i]) + '\n' f.write(line) f.close() if __name__ == '__main__': with ElapsedTimer('Tokeize'): fire.Fire(tokenize)
tokenizer_2_txt.py
可以如下运行:
python tokenizer_2_txt.py --path '/home/santanu/Downloads/Mobile_App/aclImdb/tokenizer.pickle' --path_out '/home/santanu/Downloads/Mobile_App/word_ind.txt'
上一条命令的输出日志如下:
Using TensorFlow backend. 165.235 ms: Tokenize
应用界面设计
可以使用 Android Studio 设计一个简单的移动应用界面,并将相关代码生成为 XML 文件。 正如您在以下屏幕截图(“图 7.3”)中所看到的那样,该应用包含一个简单的电影评论文本框,用户可以在其中输入他们的电影评论,并在完成后按SUBMIT
按钮。 按下SUBMIT
按钮后,评论将传递到核心应用逻辑,该逻辑将处理电影评论文本并将其传递给 TensorFlow 优化模型进行推理。
作为推理的一部分,将计算情感得分,该得分将显示在移动应用上,并同时以星级评分的形式展示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gf0skyxc-1681654125435)(https://gitcode.net/apachecn/apachecn-dl-zh/-/raw/master/docs/intel-proj-py/img/039d0647-9cac-44e2-a3d2-451570512ba1.png)]
图 7.3:移动应用用户界面页面格式
生成前面提到的移动应用视图所需的 XML 文件如下所示:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" tools:layout_editor_absoluteY="81dp"> <TextView android:id="@+id/desc" android:layout_width="100dp" android:layout_height="26dp" android:layout_marginEnd="8dp" android:layout_marginLeft="44dp" android:layout_marginRight="8dp" android:layout_marginStart="44dp" android:layout_marginTop="36dp" android:text="Movie Review" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.254" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" tools:ignore="HardcodedText" /> <EditText android:id="@+id/Review" android:layout_width="319dp" android:layout_height="191dp" android:layout_marginEnd="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="8dp" android:layout_marginStart="8dp" android:layout_marginTop="24dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/desc" /> <RatingBar android:id="@+id/ratingBar" android:layout_width="240dp" android:layout_height="49dp" android:layout_marginEnd="8dp" android:layout_marginLeft="52dp" android:layout_marginRight="8dp" android:layout_marginStart="52dp" android:layout_marginTop="28dp" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.238" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/score" tools:ignore="MissingConstraints" /> <TextView android:id="@+id/score" android:layout_width="125dp" android:layout_height="39dp" android:layout_marginEnd="8dp" android:layout_marginLeft="96dp" android:layout_marginRight="8dp" android:layout_marginStart="96dp" android:layout_marginTop="32dp" android:ems="10" android:inputType="numberDecimal" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.135" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/submit" /> <Button android:id="@+id/submit" android:layout_width="wrap_content" android:layout_height="35dp" android:layout_marginEnd="8dp" android:layout_marginLeft="136dp" android:layout_marginRight="8dp" android:layout_marginStart="136dp" android:layout_marginTop="24dp" android:text="SUBMIT" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.0" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/Review" /> </android.support.constraint.ConstraintLayout>
Python 智能项目:6~10(3)https://developer.aliyun.com/article/1426937