Guest User

Untitled

a guest
Nov 18th, 2017
120
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.25 KB | None | 0 0
  1. import dynet as dynet
  2. import random
  3. import matplotlib.pyplot as plt
  4. import numpy as np
  5.  
  6. class Network:
  7. def __init__(self, vocab, properties):
  8. self.properties = properties
  9. self.vocab = vocab
  10.  
  11. # first initialize a computation graph container (or model).
  12. self.model = dynet.Model()
  13.  
  14. # assign the algorithm for backpropagation updates.
  15. self.updater = dynet.AdamTrainer(self.model)
  16.  
  17. # create embeddings for words and tag features.
  18. self.word_embedding = self.model.add_lookup_parameters((vocab.num_words(), properties.word_embed_dim))
  19. self.tag_embedding = self.model.add_lookup_parameters((vocab.num_tag_feats(), properties.pos_embed_dim))
  20.  
  21. # assign transfer function
  22. self.transfer = dynet.rectify # can be dynet.logistic or dynet.tanh as well.
  23.  
  24. # define the input dimension for the embedding layer.
  25. # here we assume to see two words after and before and current word (meaning 5 word embeddings)
  26. # and to see the last two predicted tags (meaning two tag embeddings)
  27. self.input_dim = 5 * properties.word_embed_dim + 2 * properties.pos_embed_dim
  28.  
  29. # define the hidden layer.
  30. self.hidden_layer = self.model.add_parameters((properties.hidden_dim, self.input_dim))
  31.  
  32. # define the hidden layer bias term and initialize it as constant 0.2.
  33. self.hidden_layer_bias = self.model.add_parameters(properties.hidden_dim, init=dynet.ConstInitializer(0.2))
  34.  
  35. # define the output weight.
  36. self.output_layer = self.model.add_parameters((vocab.num_tags(), properties.hidden_dim))
  37.  
  38. # define the bias vector and initialize it as zero.
  39. self.output_bias = self.model.add_parameters(vocab.num_tags(), init=dynet.ConstInitializer(0))
  40.  
  41. def forward(self, features):
  42. # extract word and tags ids
  43. word_ids = [self.vocab.word2id(word_feat) for word_feat in features[0:5]]
  44. tag_ids = [self.vocab.feat_tag2id(tag_feat) for tag_feat in features[5:]]
  45.  
  46. # extract word embeddings and tag embeddings from features
  47. word_embeds = [self.word_embedding[wid] for wid in word_ids]
  48. tag_embeds = [self.tag_embedding[tid] for tid in tag_ids]
  49.  
  50. # concatenating all features (recall that '+' for lists is equivalent to appending two lists)
  51. embedding_layer = dynet.concatenate(word_embeds + tag_embeds)
  52.  
  53. # calculating the hidden layer
  54. # .expr() converts a parameter to a matrix expression in dynetnet (its a dynetnet-specific syntax).
  55. hidden = self.transfer(self.hidden_layer.expr() * embedding_layer + self.hidden_layer_bias.expr())
  56.  
  57. # calculating the output layer
  58. output = self.output_layer.expr() * hidden + self.output_bias.expr()
  59.  
  60. # return a list of outputs
  61. return output
  62.  
  63. def train(self, train_file, epochs):
  64. # matplotlib config
  65. loss_values = []
  66. plt.ion()
  67. ax = plt.gca()
  68. ax.set_xlim([0, 10])
  69. ax.set_ylim([0, 3])
  70. plt.title("Loss over time")
  71. plt.xlabel("Minibatch")
  72. plt.ylabel("Loss")
  73.  
  74. for i in range(epochs):
  75. print 'started epoch', (i+1)
  76. losses = []
  77. train_data = open(train_file, 'r').read().strip().split('\n')
  78.  
  79. # shuffle the training data.
  80. random.shuffle(train_data)
  81.  
  82. step = 0
  83. for line in open(train_file, 'r'):
  84. fields = line.strip().split('\t')
  85. features, label = fields[:-1], fields[-1]
  86. gold_label = self.vocab.tag2id(label)
  87. result = self.forward(features)
  88.  
  89. # getting loss with respect to negative log softmax function and the gold label.
  90. loss = dynet.pickneglogsoftmax(result, gold_label)
  91.  
  92. # appending to the minibatch losses
  93. losses.append(loss)
  94. step += 1
  95.  
  96. if len(losses) >= self.properties.minibatch_size:
  97. # now we have enough loss values to get loss for minibatch
  98. minibatch_loss = dynet.esum(losses) / len(losses)
  99.  
  100. # calling dynetnet to run forward computation for all minibatch items
  101. minibatch_loss.forward()
  102.  
  103. # getting float value of the loss for current minibatch
  104. minibatch_loss_value = minibatch_loss.value()
  105.  
  106. # printing info and plotting
  107. loss_values.append(minibatch_loss_value)
  108. if len(loss_values)%10==0:
  109. ax.set_xlim([0, len(loss_values)+10])
  110. ax.plot(loss_values)
  111. plt.draw()
  112. plt.pause(0.0001)
  113. progress = round(100 * float(step) / len(train_data), 2)
  114. print 'current minibatch loss', minibatch_loss_value, 'progress:', progress, '%'
  115.  
  116. # calling dynetnet to run backpropagation
  117. minibatch_loss.backward()
  118.  
  119. # calling dynetnet to change parameter values with respect to current backpropagation
  120. self.updater.update()
  121.  
  122. # empty the loss vector
  123. losses = []
  124.  
  125. # refresh the memory of dynetnet
  126. dynet.renew_cg()
  127.  
  128. # there are still some minibatch items in the memory but they are smaller than the minibatch size
  129. # so we ask dynet to forget them
  130. dynet.renew_cg()
  131.  
  132. def decode(self, words):
  133. # first putting two start symbols
  134. words = ['<s>', '<s>'] + words + ['</s>', '</s>']
  135. tags = ['<s>', '<s>']
  136.  
  137. for i in range(2, len(words) - 2):
  138. features = words[i - 2:i + 3] + tags[i - 2:i]
  139.  
  140. # running forward
  141. output = self.forward(features)
  142.  
  143. # getting list value of the output
  144. scores = output.npvalue()
  145.  
  146. # getting best tag
  147. best_tag_id = np.argmax(scores)
  148.  
  149. # assigning the best tag
  150. tags.append(self.vocab.tagid2tag_str(best_tag_id))
  151.  
  152. # refresh dynet memory (computation graph)
  153. dynet.renew_cg()
  154.  
  155. return tags[2:]
  156.  
  157. def load(self, filename):
  158. self.model.populate(filename)
  159.  
  160. def save(self, filename):
  161. self.model.save(filename)
Add Comment
Please, Sign In to add comment