個人工程實踐選題是《針對領域知識的中文知識圖譜自動化構建》,我將選取用於知識圖譜的分佈式表示計算框架OpenKE,代碼目錄以下圖所示:python
咱們能夠看到源代碼目錄中包括多個文件夾,其中主要爲:git
base:基礎操做代碼,包括文件讀寫,獲取樣本數,設置工做目錄等github
benchmarks:一些用於評測算法性能的數據集算法
config:設置運行所需的參數app
examples:將本框架運用於不一樣數據集上的代碼示例框架
models:本框架中包含的一些算法模型分佈式
release:由base打包獲得的動態庫ide
res:程序運行獲得的一些結果函數
除此以外咱們能夠看到在主目錄裏還有一些文件,包括許可證,框架使用樣例,編譯文件,說明文件等。能夠看出整個工程的組織比較清晰,文件夾命名比較規範。性能
下面咱們來看一段代碼:
1 #coding:utf-8 2 import numpy as np 3 import tensorflow as tf 4 from .Model import Model 5 6 if tf.__version__ > '0.12.1': 7 matmul_func = tf.matmul 8 else: 9 matmul_func = tf.batch_matmul 10 11 class TransR(Model): 12 r''' 13 TransR first projects entities from entity space to corresponding relation space 14 and then builds translations between projected entities. 15 ''' 16 def _transfer(self, transfer_matrix, embeddings): 17 return matmul_func(embeddings, transfer_matrix) 18 19 def _calc(self, h, t, r): 20 h = tf.nn.l2_normalize(h, -1) 21 t = tf.nn.l2_normalize(t, -1) 22 r = tf.nn.l2_normalize(r, -1) 23 return abs(h + r - t) 24 25 def embedding_def(self): 26 #Obtaining the initial configuration of the model 27 config = self.get_config() 28 #Defining required parameters of the model, including embeddings of entities and relations, and mapping matrices 29 self.ent_embeddings = tf.get_variable(name = "ent_embeddings", shape = [config.entTotal, config.ent_size], initializer = tf.contrib.layers.xavier_initializer(uniform = False)) 30 self.rel_embeddings = tf.get_variable(name = "rel_embeddings", shape = [config.relTotal, config.rel_size], initializer = tf.contrib.layers.xavier_initializer(uniform = False)) 31 self.transfer_matrix = tf.get_variable(name = "transfer_matrix", shape = [config.relTotal, config.ent_size * config.rel_size], initializer = tf.contrib.layers.xavier_initializer(uniform = False)) 32 self.parameter_lists = {"ent_embeddings":self.ent_embeddings, \ 33 "rel_embeddings":self.rel_embeddings, \ 34 "transfer_matrix":self.transfer_matrix} 35 36 def loss_def(self): 37 #Obtaining the initial configuration of the model 38 config = self.get_config() 39 #To get positive triples and negative triples for training 40 #The shapes of pos_h, pos_t, pos_r are (batch_size, 1) 41 #The shapes of neg_h, neg_t, neg_r are (batch_size, negative_ent + negative_rel) 42 pos_h, pos_t, pos_r = self.get_positive_instance(in_batch = True) 43 neg_h, neg_t, neg_r = self.get_negative_instance(in_batch = True) 44 #Embedding entities and relations of triples, e.g. pos_h_e, pos_t_e and pos_r_e are embeddings for positive triples 45 pos_h_e = tf.nn.embedding_lookup(self.ent_embeddings, pos_h) 46 pos_t_e = tf.nn.embedding_lookup(self.ent_embeddings, pos_t) 47 pos_r_e = tf.nn.embedding_lookup(self.rel_embeddings, pos_r) 48 neg_h_e = tf.nn.embedding_lookup(self.ent_embeddings, neg_h) 49 neg_t_e = tf.nn.embedding_lookup(self.ent_embeddings, neg_t) 50 neg_r_e = tf.nn.embedding_lookup(self.rel_embeddings, neg_r) 51 #Getting the required mapping matrices 52 pos_matrix = tf.reshape(tf.nn.embedding_lookup(self.transfer_matrix, pos_r), [-1, config.ent_size, config.rel_size]) 53 #Calculating score functions for all positive triples and negative triples 54 p_h = self._transfer(pos_matrix, pos_h_e) 55 p_t = self._transfer(pos_matrix, pos_t_e) 56 p_r = pos_r_e 57 if config.negative_rel == 0: 58 n_h = self._transfer(pos_matrix, neg_h_e) 59 n_t = self._transfer(pos_matrix, neg_t_e) 60 n_r = neg_r_e 61 else: 62 neg_matrix = tf.reshape(tf.nn.embedding_lookup(self.transfer_matrix, neg_r), [-1, config.ent_size, config.rel_size]) 63 n_h = self._transfer(neg_matrix, neg_h_e) 64 n_t = self._transfer(neg_matrix, neg_t_e) 65 n_r = neg_r_e 66 #The shape of _p_score is (batch_size, 1, hidden_size) 67 #The shape of _n_score is (batch_size, negative_ent + negative_rel, hidden_size) 68 _p_score = self._calc(p_h, p_t, p_r) 69 _n_score = self._calc(n_h, n_t, n_r) 70 #The shape of p_score is (batch_size, 1, 1) 71 #The shape of n_score is (batch_size, negative_ent + negative_rel, 1) 72 p_score = tf.reduce_sum(_p_score, -1, keep_dims = True) 73 n_score = tf.reduce_sum(_n_score, -1, keep_dims = True) 74 #Calculating loss to get what the framework will optimize 75 self.loss = tf.reduce_mean(tf.maximum(p_score - n_score + config.margin, 0)) 76 77 def predict_def(self): 78 config = self.get_config() 79 predict_h, predict_t, predict_r = self.get_predict_instance() 80 predict_h_e = tf.reshape(tf.nn.embedding_lookup(self.ent_embeddings, predict_h), [1, -1, config.ent_size]) 81 predict_t_e = tf.reshape(tf.nn.embedding_lookup(self.ent_embeddings, predict_t), [1, -1, config.ent_size]) 82 predict_r_e = tf.reshape(tf.nn.embedding_lookup(self.rel_embeddings, predict_r), [1, -1, config.rel_size]) 83 predict_matrix = tf.reshape(tf.nn.embedding_lookup(self.transfer_matrix, predict_r[0]), [1, config.ent_size, config.rel_size]) 84 h_e = tf.reshape(self._transfer(predict_matrix, predict_h_e), [-1, config.rel_size]) 85 t_e = tf.reshape(self._transfer(predict_matrix, predict_t_e), [-1, config.rel_size]) 86 r_e = predict_r_e 87 self.predict = tf.reduce_sum(self._calc(h_e, t_e, r_e), -1, keep_dims = True)
咱們能夠看到這是一個類的定義,總體比較規整,變量名和函數命名都和實際意義清晰對應,而且還有必定量的英文註釋,這有助於世界各地的開發者使用和修改這個代碼框架。
從整個代碼框架的實現來看,OpenKE項目的代碼實現層次清晰,註釋明瞭,代碼中命名規範,讓閱讀者很容易理解其表明的實際含義。除此以外,代碼的縮進以及函數間空行是比較規範的,使得代碼塊之間有清楚的界限。對於一些比較長的語句可以作到合理的換行,不至於在閱讀時不能徹底顯示。
可是代碼仍有一些不足之處:①部分代碼註釋不夠詳盡,沒有說明一些命名較簡單的變量名錶明的實際含義 ②整個項目缺少對源代碼組織以及代碼編寫理論的介紹,使得初學者不易理清代碼和理論之間的對應關係。
下面我將列舉一些Python代碼風格規範,資料來源於谷歌開源項目風格指南:
不要在行尾加分號, 也不要用分號將兩條命令放在同一行。
每行不超過80個字符
例外:
不要使用反斜槓鏈接行。
Python會將圓括號,中括號和花括號中的行隱式的鏈接起來 ,你能夠利用這個特色。 若是須要,你能夠在表達式外圍增長一對額外的圓括號。若是一個文本字符串在一行放不下, 可使用圓括號來實現隱式行鏈接。在註釋中,若是必要,將長的URL放在一行上。
除非是用於實現行鏈接,不然不要在返回語句或條件語句中使用括號,不過在元組兩邊使用括號是能夠的。
用4個空格來縮進代碼,絕對不要用tab,也不要tab和空格混用。 對於行鏈接的狀況,你應該要麼垂直對齊換行的元素, 或者使用4空格的懸掛式縮進(這時第一行不該該有參數)。
按照標準的排版規範來使用標點兩邊的空格,括號內不要有空格。不要在逗號、分號、冒號前面加空格,但應該在它們後面加(除了在行尾)。參數列表,、索引或切片的左括號前不該加空格。在二元操做符兩邊都加上一個空格,好比賦值(=), 比較(==, <, >, !=, <>, <=, >=, in, not in, is, is not), 布爾(and, or, not)。至於算術操做符兩邊的空格該如何使用, 須要你本身好好判斷。當’=’用於指示關鍵字參數或默認參數值時, 不要在其兩側使用空格。不要用空格來垂直對齊多行間的標記,由於這會成爲維護的負擔(適用於:, #, =等)。
一般每一個語句應該獨佔一行,不過, 若是測試結果與測試語句在一行放得下,你也能夠將它們放在同一行。 若是是if語句, 只有在沒有else時才能這樣作。特別地, 毫不要對 try/except
這樣作, 由於try和except不能放在同一行。
命名約定
- 所謂」內部(Internal)」表示僅模塊內可用, 或者, 在類內是保護或私有的.
- 用單下劃線(_)開頭表示模塊變量或函數是protected的(使用from module import *時不會包含).
- 用雙下劃線(__)開頭的實例變量或方法表示類內私有.
- 將相關的類和頂級函數放在同一個模塊裏. 不像Java, 不必限制一個類一個模塊.
- 對類名使用大寫字母開頭的單詞(如CapWords, 即Pascal風格), 可是模塊名應該用小寫加下劃線的方式(如lower_with_under.py). 儘管已經有不少現存的模塊使用相似於CapWords.py這樣的命名, 但如今已經不鼓勵這樣作, 由於若是模塊名碰巧和類名一致, 這會讓人困擾.
應該避免的名稱
- 單字符名稱, 除了計數器和迭代器.
- 包/模塊名中的連字符(-)
- 雙下劃線開頭並結尾的名稱(Python保留, 例如__init__)