{"action":"created","comment":{"url":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/comments/230254373","pull_request_review_id":170951101,"id":230254373,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIzMDI1NDM3Mw==","diff_hunk":"@@ -0,0 +1,374 @@\n+# Word Embeddings Training and Evaluation\n+\n+```{.python .input}\n+import warnings\n+warnings.filterwarnings('ignore')\n+\n+import itertools\n+import time\n+import math\n+import logging\n+import random\n+\n+import mxnet as mx\n+import gluonnlp as nlp\n+import numpy as np\n+from scipy import stats\n+\n+# context = mx.cpu()  # Enable this to run on CPU\n+context = mx.gpu(0)  # Enable this to run on GPU\n+```\n+\n+### Data\n+Here we use the Text8 corpus from the [Large Text Compression\n+Benchmark](http://mattmahoney.net/dc/textdata.html) which includes the first\n+100\n+MB of cleaned text from the English Wikipedia.\n+\n+```{.python .input}\n+text8 = nlp.data.Text8()\n+print('# sentences:', len(text8))\n+for sentence in text8[:3]:\n+    print('# tokens:', len(sentence), sentence[:5])\n+```\n+\n+Given the tokenized data, we first count all tokens and then construct a\n+vocabulary of all tokens that occur at least 5 times in the dataset. The\n+vocabulary contains a one-to-one mapping between tokens and integers (also\n+called indices or short idx).\n+\n+We further store the frequency count of each\n+token in the vocabulary as we will require this information later on for\n+sampling random negative (or noise) words. Finally we replace all tokens with\n+their integer representation based on the vocabulary.\n+\n+```{.python .input}\n+counter = nlp.data.count_tokens(itertools.chain.from_iterable(text8))\n+vocab = nlp.Vocab(counter, unknown_token=None, padding_token=None,\n+                  bos_token=None, eos_token=None, min_freq=5)\n+idx_to_counts = [counter[w] for w in vocab.idx_to_token]\n+\n+def code(sentence):\n+    return [vocab[token] for token in sentence if token in vocab]\n+\n+text8 = text8.transform(code, lazy=False)\n+\n+print('# sentences:', len(text8))\n+for sentence in text8[:3]:\n+    print('# tokens:', len(sentence), sentence[:5])\n+```\n+\n+Next we need to transform the coded Text8 dataset into batches useful for\n+training an embedding model.\n+In this tutorial we train with the SkipGram\n+objective made popular by [1].\n+\n+For SkipGram, we sample pairs of co-occurring\n+words from the corpus.\n+Two words are said to co-occur if they occurr with\n+distance less then a specified *window* size.\n+The *window* size is usually\n+chosen around 5.\n+\n+For obtaining the samples from the corpus, we can shuffle the\n+sentences and the proceed linearly through each sentence, considering each word\n+as well as all the words in it's window. In this case, we call the current word\n+in focus the center word, and the words in it's window the context words.\n+GluonNLP contains `gluonnlp.data.EmbeddingCenterContextBatchify` batchify\n+transformation, that takes a corpus, such as the coded Text8 we have here, and\n+returns a `DataStream` of batches of center and context words.\n+\n+\n+\n+To obtain good\n+results, each sentence is further subsampled, meaning that words are deleted\n+with a probability proportional to their frequency.\n+[1] proposes to discard\n+individual occurences of words from the dataset with probability\n+\n+$$P(w_i) = 1 -\n+\\sqrt{\\frac{t}{f(w_i)}}$$\n+\n+where $f(w_i)$ is the frequency with which a word is\n+observed in a dataset and $t$ is a subsampling constant typically chosen around\n+$10^{-5}$.\n+[1] has also shown that the final performance is improved if the\n+window size is chosen  uniformly random for each center words out of the range\n+[1, *window*].\n+\n+For this notebook, we are interested in training a fastText\n+embedding model [2]. A fastText model not only associates a embedding vector to\n+each token in the vocabulary, but also to a pre-specified number of subwords.\n+Commonly 2 million subword vectors are obtained and each subword vector is\n+associated with zero, one or multiple character-ngrams. The mapping between\n+character-ngrams and subwords is based on a hash function.\n+The *final* embedding\n+vector of a token is the mean of the vectors associated with the token and all\n+character-ngrams occuring in the string representation of the token. Thereby a\n+fastText embedding model can compute meaningful embedding vectors for tokens\n+that were not seen during training.\n+\n+For this notebook, we have prepared a\n+helper function `transform_data` which builds a series of transformations of the\n+`text8` `Dataset` created above, applying \"tricks\" mentioned before. It returns\n+a `DataStream` over batches as well as a batchify_fn function that applied to a\n+batch looks up and includes the fastText subwords associated with the center\n+words and finally the subword function that can be used to obtain the subwords\n+of a given string representation of a token. We will take a closer look at the\n+subword function shortly.\n+\n+Note that the number of subwords is potentially\n+different for every word. Therefore the batchify_fn represents a word with its\n+subwords as a row in a compressed sparse row (CSR) matrix. Take a look at\n+https://mxnet.incubator.apache.org/tutorials/sparse/csr.html if you are not\n+familia with CSR.  Separating the batchify_fn from the previous word-pair\n+sampling is useful, as it allows to parallelize the CSR matrix construction over\n+multiple CPU cores for separate batches.\n+\n+You can find it in `data.py` in the\n+archive that can be downloaded via the Download button at the top of this page.\n+- [1] Mikolov, Tomas, et al. “Distributed representations of words and phrases\n+and their compositionality.”\n+   Advances in neural information processing\n+systems. 2013.\n+- [2] Bojanowski et al., \"Enriching Word Vectors with Subword\n+Information\" Transactions of the Association for Computational Linguistics 2017\n+\n+```{.python .input}\n+from data import transform_data\n+\n+batch_size=4096\n+text8 = nlp.data.SimpleDataStream([text8])  # input is a stream of datasets, here just 1. Allows scaling to larger corpora that don't fit in memory\n+data, batchify_fn, subword_function = transform_data(\n+    text8, vocab, idx_to_counts, cbow=False, ngrams=[3,4,5,6], ngram_buckets=10000, batch_size=batch_size, window_size=5)\n+```\n+\n+```{.python .input}\n+batches = data.transform(batchify_fn)\n+```\n+\n+## Subwords\n+\n+`gluonnlp` provides the concept of a SubwordFunction which maps\n+words to a list of indices representing their subword.\n+Possible SubwordFunctions\n+include mapping a word to the sequence of it's characters/bytes or hashes of all\n+its ngrams.\n+\n+FastText models use a hash function to map each ngram of a word to\n+a number in range `[0, num_subwords)`. We include the same hash function.\n+Above\n+transform_data has also returned a `subword_function` object. Let's try it with\n+a few words:\n+\n+```{.python .input}\n+idx_to_subwordidxs = subword_function(vocab.idx_to_token)\n+for word, subwords in zip(vocab.idx_to_token[:3], idx_to_subwordidxs[:3]):\n+    print('<'+word+'>', subwords, sep = '\\t')\n+```\n+\n+### Model\n+\n+Here we define a SkipGram model for training fastText embeddings.\n+For\n+Skip-Gram, the model consists of two independent embedding networks.\n+One for the\n+center words, and one for the context words.\n+For center words, subwords are\n+taken into account while for context words only the token itself is taken into\n+account.\n+\n+GluonNLP provides a `nlp.model.train.FasttextEmbeddingModel` Block\n+which defines the fastText style embedding with subword support.\n+It can be used\n+for training, but also supports loading models trained with the original C++\n+fastText library from `.bin` files.\n+After training, vectors for arbitrary words\n+can be looked up via `embedding[['a', 'list', 'of', 'potentially', 'unknown',\n+'words']]` where `embedding` is a `nlp.model.train.FasttextEmbeddingModel`.\n+\n+In\n+the `model.py` script we provide a definition for the fastText model for the\n+SkipGram objective.\n+The model definition is a Gluon HybridBlock, meaning that\n+the complete forward / backward pass are compiled and executed directly in the\n+MXNet backend. Not only does the Block include the `FasttextEmbeddingModel` for\n+the center words and a simple embedding matrix for the context words, but it\n+also takes care of sampling a specified number of noise words for each center-\n+context pair. These noise words are called negatives, as the resulting center-\n+negative pair is unlikely to occur in the dataset. The model then must learn\n+which word-pairs are negatives and which ones are real. Thereby it obtains\n+meaningful word and subword vectors for all considered tokens. The negatives are\n+sampled from the smoothed unigram frequency distribution.\n+\n+Let's instantiate and\n+initialize the model. We also create a trainer object for updating the\n+parameters with AdaGrad.\n+Finally we print a summary of the model.\n+\n+```{.python .input}\n+from model import SG as SkipGramNet\n+\n+emsize = 300\n+num_negatives = 5\n+\n+negatives_weights = mx.nd.array(idx_to_counts)\n+embedding = SkipGramNet(\n+    vocab.token_to_idx, emsize, batch_size, negatives_weights, subword_function, num_negatives=5, smoothing=0.75)\n+embedding.initialize(ctx=context)\n+embedding.hybridize()\n+trainer = mx.gluon.Trainer(embedding.collect_params(), 'adagrad', dict(learning_rate=0.05))\n+\n+print(embedding)\n+```\n+\n+Let's take a look at the documentation of the forward pass.\n+\n+```{.python .input}\n+print(SkipGramNet.hybrid_forward.__doc__)\n+```\n+\n+Before we start training, let's examine the quality of our randomly initialized\n+embeddings:\n+\n+```{.python .input}\n+def norm_vecs_by_row(x):\n+    return x / (mx.nd.sum(x * x, axis=1) + 1e-10).sqrt().reshape((-1, 1))\n+\n+\n+def get_k_closest_tokens(vocab, embedding, k, word):\n+    word_vec = norm_vecs_by_row(embedding[[word]])\n+    vocab_vecs = norm_vecs_by_row(embedding[vocab.idx_to_token])\n+    dot_prod = mx.nd.dot(vocab_vecs, word_vec.T)\n+    indices = mx.nd.topk(\n+        dot_prod.reshape((len(vocab.idx_to_token), )),\n+        k=k + 1,\n+        ret_typ='indices')\n+    indices = [int(i.asscalar()) for i in indices]\n+    result = [vocab.idx_to_token[i] for i in indices[1:]]\n+    print('closest tokens to \"%s\": %s' % (word, \", \".join(result)))\n+```\n+\n+```{.python .input}\n+example_token = \"vector\"\n+get_k_closest_tokens(vocab, embedding, 10, example_token)\n+```\n+\n+We can see that in the randomly initialized fastText model the closest tokens to\n+\"vector\" are based on overlapping ngrams.\n+\n+### Training\n+\n+Thanks to the Gluon data pipeline and the HybridBlock handling all\n+complexity, our training code is very simple.\n+We iterate over all batches, move\n+them to the appropriate context (GPU), do forward, backward and parameter update\n+and finally include some helpful print statements for following the training\n+process.\n+\n+```{.python .input}\n+log_interval = 50\n+\n+def train_embedding(num_epochs):\n+    for epoch in range(1, num_epochs + 1):\n+        start_time = time.time()\n+        train_l_sum = 0\n+        num_samples = 0\n+        \n+        print('Beginnign epoch %d and resampling data.' % epoch)\n+        for i, batch in enumerate(batches):\n+            batch = [array.as_in_context(context) for array in batch]\n+            with mx.autograd.record():\n+                l = embedding(*batch)\n+            l.backward()\n+            trainer.step(1)\n+            \n+            train_l_sum += l.sum()\n+            num_samples += l.shape[0]\n+            if i % log_interval == 0:\n+                mx.nd.waitall()\n+                wps = num_samples / (time.time() - start_time)\n+                print('epoch %d, time %.2fs, iteration %d, throughput=%.2fK wps'\n+                      % (epoch, time.time() - start_time, i, wps / 1000))\n+\n+        print('epoch %d, time %.2fs, train loss %.2f'\n+              % (epoch, time.time() - start_time,\n+                 train_l_sum.asscalar() / num_samples))\n+        get_k_closest_tokens(vocab, embedding, 10, example_token)\n+        print(\"\")\n+```\n+\n+```{.python .input}\n+train_embedding(num_epochs=1)\n+```\n+\n+### Word Similarity and Relatedness Task\n+\n+Word embeddings should capture the\n+relationsship between words in natural language.\n+In the Word Similarity and\n+Relatedness Task word embeddings are evaluated by comparing word similarity\n+scores computed from a pair of words with human labels for the similarity or\n+relatedness of the pair.\n+\n+`gluonnlp` includes a number of common datasets for\n+the Word Similarity and Relatedness Task. The included datasets are listed in\n+the [API documentation](http://gluon-nlp.mxnet.io/api/data.html#word-embedding-\n+evaluation-datasets). We use several of them in the evaluation example below.\n+We first show a few samples from the WordSim353 dataset, to get an overall\n+feeling of the Dataset structur\n+\n+### Evaluation\n+\n+Thanks to the subword support of the `FasttextEmbeddingModel` we\n+can evaluate on all words in the evaluation dataset,\n+not only the ones that we\n+observed during training.\n+\n+We first compute a list of tokens in our evaluation\n+dataset and then create a embedding matrix for them based on the fastText model.\n+\n+```{.python .input}\n+rw = nlp.data.RareWords()\n+rw_tokens  = list(set(itertools.chain.from_iterable((d[0], d[1]) for d in rw)))\n+\n+rw_token_embedding = nlp.embedding.TokenEmbedding(unknown_token=None, allow_extend=True)\n+rw_token_embedding[rw_tokens]= embedding[rw_tokens]\n+\n+print('There are', len(rw_tokens), 'unique tokens in the RareWords dataset. Examples are:')\n+for i in range(5):\n+    print('\\t', rw[i])\n+print('The imputed TokenEmbedding has shape', rw_token_embedding.idx_to_vec.shape)\n+```\n+\n+```{.python .input}\n+evaluator = nlp.embedding.evaluation.WordEmbeddingSimilarity(\n+    idx_to_vec=rw_token_embedding.idx_to_vec,\n+    similarity_function=\"CosineSimilarity\")\n+evaluator.initialize(ctx=context)\n+evaluator.hybridize()\n+```\n+\n+```{.python .input}\n+words1, words2, scores = zip(*([rw_token_embedding.token_to_idx[d[0]],\n+                                rw_token_embedding.token_to_idx[d[1]],\n+                                d[2]] for d in rw))\n+words1 = mx.nd.array(words1, ctx=context)\n+words2 = mx.nd.array(words2, ctx=context)\n+```\n+\n+```{.python .input}\n+pred_similarity = evaluator(words1, words2)\n+sr = stats.spearmanr(pred_similarity.asnumpy(), np.array(scores))\n+print('Spearman rank correlation on {} pairs of {}: {}'.format(\n+    len(words1), rw.__class__.__name__, sr.correlation.round(3)))\n+```\n+\n+# Further information","path":"docs/examples/word_embedding/word_embedding_training.md","position":367,"original_position":367,"commit_id":"e8d1793a750d38657329de464f79d82babf2fc04","original_commit_id":"e8d1793a750d38657329de464f79d82babf2fc04","user":{"login":"szha","id":2626883,"node_id":"MDQ6VXNlcjI2MjY4ODM=","avatar_url":"https://avatars2.githubusercontent.com/u/2626883?v=4","gravatar_id":"","url":"https://api.github.com/users/szha","html_url":"https://github.com/szha","followers_url":"https://api.github.com/users/szha/followers","following_url":"https://api.github.com/users/szha/following{/other_user}","gists_url":"https://api.github.com/users/szha/gists{/gist_id}","starred_url":"https://api.github.com/users/szha/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/szha/subscriptions","organizations_url":"https://api.github.com/users/szha/orgs","repos_url":"https://api.github.com/users/szha/repos","events_url":"https://api.github.com/users/szha/events{/privacy}","received_events_url":"https://api.github.com/users/szha/received_events","type":"User","site_admin":false},"body":"Title level is incorrect, as it's showing up on the main page. http://gluon-nlp-staging.s3-accelerate.dualstack.amazonaws.com/PR-384/20/examples/word_embedding/word_embedding_training.html#Further-information","created_at":"2018-11-02T02:20:01Z","updated_at":"2018-11-02T02:20:01Z","html_url":"https://github.com/dmlc/gluon-nlp/pull/384#discussion_r230254373","pull_request_url":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/384","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/comments/230254373"},"html":{"href":"https://github.com/dmlc/gluon-nlp/pull/384#discussion_r230254373"},"pull_request":{"href":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/384"}}},"pull_request":{"url":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/384","id":226279178,"node_id":"MDExOlB1bGxSZXF1ZXN0MjI2Mjc5MTc4","html_url":"https://github.com/dmlc/gluon-nlp/pull/384","diff_url":"https://github.com/dmlc/gluon-nlp/pull/384.diff","patch_url":"https://github.com/dmlc/gluon-nlp/pull/384.patch","issue_url":"https://api.github.com/repos/dmlc/gluon-nlp/issues/384","number":384,"state":"open","locked":false,"title":"CSR for variable length data in embedding training","user":{"login":"leezu","id":946903,"node_id":"MDQ6VXNlcjk0NjkwMw==","avatar_url":"https://avatars1.githubusercontent.com/u/946903?v=4","gravatar_id":"","url":"https://api.github.com/users/leezu","html_url":"https://github.com/leezu","followers_url":"https://api.github.com/users/leezu/followers","following_url":"https://api.github.com/users/leezu/following{/other_user}","gists_url":"https://api.github.com/users/leezu/gists{/gist_id}","starred_url":"https://api.github.com/users/leezu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leezu/subscriptions","organizations_url":"https://api.github.com/users/leezu/orgs","repos_url":"https://api.github.com/users/leezu/repos","events_url":"https://api.github.com/users/leezu/events{/privacy}","received_events_url":"https://api.github.com/users/leezu/received_events","type":"User","site_admin":false},"body":"## Description ##\r\nUse sparse CSR matrices instead of masking to handle variable length inputs in embedding training.\r\n\r\n## Checklist ##\r\n### Essentials ###\r\n- [ ] Changes are complete (i.e. I finished coding on this PR)\r\n- [X] All changes have test coverage\r\n- [X] Code is well-documented\r\n\r\n### Changes ###\r\n- [X] CSR for variable length data in embedding training\r\n- [X] Allow use of multiple GPUs for embedding training scripts\r\n\r\n### Comments ###\r\n- This is faster than the previous implementation. It also allows Hybridization.\r\n- The refactored numba code for IO and preparing the sparse array containing words and subwords should allow further speedup is not yet parallelized. It takes around 60% of python time according to https://github.com/uber/pyflame. Depending on the batch_size, the blocking nature of nd.sparse.csr_matrix may also induce some slowdown.\r\n- Pending verification of training results","created_at":"2018-10-27T08:30:49Z","updated_at":"2018-11-02T02:20:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"134007ae95f171c43482437942f3ffebe5efc9c4","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/384/commits","review_comments_url":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/384/comments","review_comment_url":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dmlc/gluon-nlp/issues/384/comments","statuses_url":"https://api.github.com/repos/dmlc/gluon-nlp/statuses/e8d1793a750d38657329de464f79d82babf2fc04","head":{"label":"leezu:csr","ref":"csr","sha":"e8d1793a750d38657329de464f79d82babf2fc04","user":{"login":"leezu","id":946903,"node_id":"MDQ6VXNlcjk0NjkwMw==","avatar_url":"https://avatars1.githubusercontent.com/u/946903?v=4","gravatar_id":"","url":"https://api.github.com/users/leezu","html_url":"https://github.com/leezu","followers_url":"https://api.github.com/users/leezu/followers","following_url":"https://api.github.com/users/leezu/following{/other_user}","gists_url":"https://api.github.com/users/leezu/gists{/gist_id}","starred_url":"https://api.github.com/users/leezu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leezu/subscriptions","organizations_url":"https://api.github.com/users/leezu/orgs","repos_url":"https://api.github.com/users/leezu/repos","events_url":"https://api.github.com/users/leezu/events{/privacy}","received_events_url":"https://api.github.com/users/leezu/received_events","type":"User","site_admin":false},"repo":{"id":131359655,"node_id":"MDEwOlJlcG9zaXRvcnkxMzEzNTk2NTU=","name":"gluon-nlp","full_name":"leezu/gluon-nlp","private":false,"owner":{"login":"leezu","id":946903,"node_id":"MDQ6VXNlcjk0NjkwMw==","avatar_url":"https://avatars1.githubusercontent.com/u/946903?v=4","gravatar_id":"","url":"https://api.github.com/users/leezu","html_url":"https://github.com/leezu","followers_url":"https://api.github.com/users/leezu/followers","following_url":"https://api.github.com/users/leezu/following{/other_user}","gists_url":"https://api.github.com/users/leezu/gists{/gist_id}","starred_url":"https://api.github.com/users/leezu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/leezu/subscriptions","organizations_url":"https://api.github.com/users/leezu/orgs","repos_url":"https://api.github.com/users/leezu/repos","events_url":"https://api.github.com/users/leezu/events{/privacy}","received_events_url":"https://api.github.com/users/leezu/received_events","type":"User","site_admin":false},"html_url":"https://github.com/leezu/gluon-nlp","description":"NLP made easy","fork":true,"url":"https://api.github.com/repos/leezu/gluon-nlp","forks_url":"https://api.github.com/repos/leezu/gluon-nlp/forks","keys_url":"https://api.github.com/repos/leezu/gluon-nlp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/leezu/gluon-nlp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/leezu/gluon-nlp/teams","hooks_url":"https://api.github.com/repos/leezu/gluon-nlp/hooks","issue_events_url":"https://api.github.com/repos/leezu/gluon-nlp/issues/events{/number}","events_url":"https://api.github.com/repos/leezu/gluon-nlp/events","assignees_url":"https://api.github.com/repos/leezu/gluon-nlp/assignees{/user}","branches_url":"https://api.github.com/repos/leezu/gluon-nlp/branches{/branch}","tags_url":"https://api.github.com/repos/leezu/gluon-nlp/tags","blobs_url":"https://api.github.com/repos/leezu/gluon-nlp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/leezu/gluon-nlp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/leezu/gluon-nlp/git/refs{/sha}","trees_url":"https://api.github.com/repos/leezu/gluon-nlp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/leezu/gluon-nlp/statuses/{sha}","languages_url":"https://api.github.com/repos/leezu/gluon-nlp/languages","stargazers_url":"https://api.github.com/repos/leezu/gluon-nlp/stargazers","contributors_url":"https://api.github.com/repos/leezu/gluon-nlp/contributors","subscribers_url":"https://api.github.com/repos/leezu/gluon-nlp/subscribers","subscription_url":"https://api.github.com/repos/leezu/gluon-nlp/subscription","commits_url":"https://api.github.com/repos/leezu/gluon-nlp/commits{/sha}","git_commits_url":"https://api.github.com/repos/leezu/gluon-nlp/git/commits{/sha}","comments_url":"https://api.github.com/repos/leezu/gluon-nlp/comments{/number}","issue_comment_url":"https://api.github.com/repos/leezu/gluon-nlp/issues/comments{/number}","contents_url":"https://api.github.com/repos/leezu/gluon-nlp/contents/{+path}","compare_url":"https://api.github.com/repos/leezu/gluon-nlp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/leezu/gluon-nlp/merges","archive_url":"https://api.github.com/repos/leezu/gluon-nlp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/leezu/gluon-nlp/downloads","issues_url":"https://api.github.com/repos/leezu/gluon-nlp/issues{/number}","pulls_url":"https://api.github.com/repos/leezu/gluon-nlp/pulls{/number}","milestones_url":"https://api.github.com/repos/leezu/gluon-nlp/milestones{/number}","notifications_url":"https://api.github.com/repos/leezu/gluon-nlp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/leezu/gluon-nlp/labels{/name}","releases_url":"https://api.github.com/repos/leezu/gluon-nlp/releases{/id}","deployments_url":"https://api.github.com/repos/leezu/gluon-nlp/deployments","created_at":"2018-04-28T01:26:20Z","updated_at":"2018-10-30T04:28:56Z","pushed_at":"2018-11-01T12:36:40Z","git_url":"git://github.com/leezu/gluon-nlp.git","ssh_url":"git@github.com:leezu/gluon-nlp.git","clone_url":"https://github.com/leezu/gluon-nlp.git","svn_url":"https://github.com/leezu/gluon-nlp","homepage":"http://gluon-nlp.mxnet.io","size":3013,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"dmlc:master","ref":"master","sha":"8b7d53ea5bacaf34aeeafed01d894715f63807ae","user":{"login":"dmlc","id":11508361,"node_id":"MDEyOk9yZ2FuaXphdGlvbjExNTA4MzYx","avatar_url":"https://avatars2.githubusercontent.com/u/11508361?v=4","gravatar_id":"","url":"https://api.github.com/users/dmlc","html_url":"https://github.com/dmlc","followers_url":"https://api.github.com/users/dmlc/followers","following_url":"https://api.github.com/users/dmlc/following{/other_user}","gists_url":"https://api.github.com/users/dmlc/gists{/gist_id}","starred_url":"https://api.github.com/users/dmlc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dmlc/subscriptions","organizations_url":"https://api.github.com/users/dmlc/orgs","repos_url":"https://api.github.com/users/dmlc/repos","events_url":"https://api.github.com/users/dmlc/events{/privacy}","received_events_url":"https://api.github.com/users/dmlc/received_events","type":"Organization","site_admin":false},"repo":{"id":128121076,"node_id":"MDEwOlJlcG9zaXRvcnkxMjgxMjEwNzY=","name":"gluon-nlp","full_name":"dmlc/gluon-nlp","private":false,"owner":{"login":"dmlc","id":11508361,"node_id":"MDEyOk9yZ2FuaXphdGlvbjExNTA4MzYx","avatar_url":"https://avatars2.githubusercontent.com/u/11508361?v=4","gravatar_id":"","url":"https://api.github.com/users/dmlc","html_url":"https://github.com/dmlc","followers_url":"https://api.github.com/users/dmlc/followers","following_url":"https://api.github.com/users/dmlc/following{/other_user}","gists_url":"https://api.github.com/users/dmlc/gists{/gist_id}","starred_url":"https://api.github.com/users/dmlc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dmlc/subscriptions","organizations_url":"https://api.github.com/users/dmlc/orgs","repos_url":"https://api.github.com/users/dmlc/repos","events_url":"https://api.github.com/users/dmlc/events{/privacy}","received_events_url":"https://api.github.com/users/dmlc/received_events","type":"Organization","site_admin":false},"html_url":"https://github.com/dmlc/gluon-nlp","description":"NLP made easy","fork":false,"url":"https://api.github.com/repos/dmlc/gluon-nlp","forks_url":"https://api.github.com/repos/dmlc/gluon-nlp/forks","keys_url":"https://api.github.com/repos/dmlc/gluon-nlp/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dmlc/gluon-nlp/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dmlc/gluon-nlp/teams","hooks_url":"https://api.github.com/repos/dmlc/gluon-nlp/hooks","issue_events_url":"https://api.github.com/repos/dmlc/gluon-nlp/issues/events{/number}","events_url":"https://api.github.com/repos/dmlc/gluon-nlp/events","assignees_url":"https://api.github.com/repos/dmlc/gluon-nlp/assignees{/user}","branches_url":"https://api.github.com/repos/dmlc/gluon-nlp/branches{/branch}","tags_url":"https://api.github.com/repos/dmlc/gluon-nlp/tags","blobs_url":"https://api.github.com/repos/dmlc/gluon-nlp/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dmlc/gluon-nlp/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dmlc/gluon-nlp/git/refs{/sha}","trees_url":"https://api.github.com/repos/dmlc/gluon-nlp/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dmlc/gluon-nlp/statuses/{sha}","languages_url":"https://api.github.com/repos/dmlc/gluon-nlp/languages","stargazers_url":"https://api.github.com/repos/dmlc/gluon-nlp/stargazers","contributors_url":"https://api.github.com/repos/dmlc/gluon-nlp/contributors","subscribers_url":"https://api.github.com/repos/dmlc/gluon-nlp/subscribers","subscription_url":"https://api.github.com/repos/dmlc/gluon-nlp/subscription","commits_url":"https://api.github.com/repos/dmlc/gluon-nlp/commits{/sha}","git_commits_url":"https://api.github.com/repos/dmlc/gluon-nlp/git/commits{/sha}","comments_url":"https://api.github.com/repos/dmlc/gluon-nlp/comments{/number}","issue_comment_url":"https://api.github.com/repos/dmlc/gluon-nlp/issues/comments{/number}","contents_url":"https://api.github.com/repos/dmlc/gluon-nlp/contents/{+path}","compare_url":"https://api.github.com/repos/dmlc/gluon-nlp/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dmlc/gluon-nlp/merges","archive_url":"https://api.github.com/repos/dmlc/gluon-nlp/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dmlc/gluon-nlp/downloads","issues_url":"https://api.github.com/repos/dmlc/gluon-nlp/issues{/number}","pulls_url":"https://api.github.com/repos/dmlc/gluon-nlp/pulls{/number}","milestones_url":"https://api.github.com/repos/dmlc/gluon-nlp/milestones{/number}","notifications_url":"https://api.github.com/repos/dmlc/gluon-nlp/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dmlc/gluon-nlp/labels{/name}","releases_url":"https://api.github.com/repos/dmlc/gluon-nlp/releases{/id}","deployments_url":"https://api.github.com/repos/dmlc/gluon-nlp/deployments","created_at":"2018-04-04T20:57:13Z","updated_at":"2018-11-02T01:22:02Z","pushed_at":"2018-11-01T06:22:14Z","git_url":"git://github.com/dmlc/gluon-nlp.git","ssh_url":"git@github.com:dmlc/gluon-nlp.git","clone_url":"https://github.com/dmlc/gluon-nlp.git","svn_url":"https://github.com/dmlc/gluon-nlp","homepage":"http://gluon-nlp.mxnet.io","size":5458,"stargazers_count":1034,"watchers_count":1034,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":208,"mirror_url":null,"archived":false,"open_issues_count":49,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0","node_id":"MDc6TGljZW5zZTI="},"forks":208,"open_issues":49,"watchers":1034,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/384"},"html":{"href":"https://github.com/dmlc/gluon-nlp/pull/384"},"issue":{"href":"https://api.github.com/repos/dmlc/gluon-nlp/issues/384"},"comments":{"href":"https://api.github.com/repos/dmlc/gluon-nlp/issues/384/comments"},"review_comments":{"href":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/384/comments"},"review_comment":{"href":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dmlc/gluon-nlp/pulls/384/commits"},"statuses":{"href":"https://api.github.com/repos/dmlc/gluon-nlp/statuses/e8d1793a750d38657329de464f79d82babf2fc04"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"szha"}}