From 7a51176b487b3d59b8ce71be210715f62595e46f Mon Sep 17 00:00:00 2001 From: Hai Liang Wang Date: Sat, 12 Aug 2017 19:36:57 +0800 Subject: [PATCH] Add deep_qa_1 as baseline --- .gitignore | 1 - README.md | 77 +++----------- Requirements.txt | 10 ++ deep_qa_1/README.md | 7 ++ deep_qa_1/__init__.py | 0 deep_qa_1/baseline_acc.png | Bin 0 -> 24377 bytes deep_qa_1/baseline_loss.png | Bin 0 -> 51067 bytes deep_qa_1/data.py | 182 +++++++++++++++++++++++++++++++++ deep_qa_1/network.py | 170 ++++++++++++++++++++++++++++++ tmp/.gitignore | 2 + visual/__init__.py | 0 visual/accuracy.py | 71 +++++++++++++ visual/loss.py | 72 +++++++++++++ visual/tensorflowvisu.mplstyle | 55 ++++++++++ 14 files changed, 585 insertions(+), 62 deletions(-) create mode 100644 Requirements.txt create mode 100644 deep_qa_1/README.md create mode 100644 deep_qa_1/__init__.py create mode 100644 deep_qa_1/baseline_acc.png create mode 100644 deep_qa_1/baseline_loss.png create mode 100755 deep_qa_1/data.py create mode 100755 deep_qa_1/network.py create mode 100644 tmp/.gitignore create mode 100755 visual/__init__.py create mode 100755 visual/accuracy.py create mode 100755 visual/loss.py create mode 100644 visual/tensorflowvisu.mplstyle diff --git a/.gitignore b/.gitignore index 0d6957c..1ade742 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ node_modules *.pyc __pycache__ _env -tmp diff --git a/README.md b/README.md index bf4b29e..9d721ab 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,34 @@ -# insuranceqa-corpus-zh -保险行业语料库 +# 保险行业语料库 ![](https://camo.githubusercontent.com/ae91a5698ad80d3fe8e0eb5a4c6ee7170e088a7d/687474703a2f2f37786b6571692e636f6d312e7a302e676c622e636c6f7564646e2e636f6d2f61692f53637265656e25323053686f74253230323031372d30342d30342532306174253230382e32302e3437253230504d2e706e67) -## Welcome +# Welcome -该语料库包含从网站[Insurance Library](http://www.insurancelibrary.com/) 收集的问题和答案。 +Baseline model for [insuranceqa-corpus-zh](https://github.com/Samurais/insuranceqa-corpus-zh/wiki). -据我们所知,这是保险领域首个开放的QA语料库: +Baseline: mini-batch size = 100, hidden_layers = [100, 50], lr = 0.0001. -* 该语料库的内容由现实世界的用户提出,高质量的答案由具有深度领域知识的专业人士提供。 所以这是一个具有真正价值的语料,而不是玩具。 +![](./deep_qa_1/baseline_acc.png) -* 在上述论文中,语料库用于答复选择任务。 另一方面,这种语料库的其他用法也是可能的。 例如,通过阅读理解答案,观察学习等自主学习,使系统能够最终拿出自己的看不见的问题的答案。 +![](./deep_qa_1/baseline_loss.png) -欢迎任何进一步增加此数据集的想法。 +> Epoch 25, total step 36400, accuracy 0.9031, cost 1.056221. -## 语料数据 +## Deps +Python3+ -| - | 问题 | 答案 | 词汇(英语) | -| ------------- |-------------| ----- | ----- | -| 训练 | 12,889 | 21,325 | 107,889 | -| 验证 | 2,000 | 3354 | 16,931 | -| 测试 | 2,000 | 3308 | 16,815 | - -每条数据包括问题的中文,英文,答案的正例,答案的负例。案的正例至少1项,基本上在*1-5*条,都是正确答案。答案的负例有*200*条,负例根据问题使用检索的方式建立,所以和问题是相关的,但却不是正确答案。 - -``` -{ - "INDEX": { - "zh": "中文", - "en": "英文", - "domain": "保险种类", - "answers": [""] # 答案正例列表 - "negatives": [""] # 答案负例列表 - }, - more ... -} -``` - -* 训练:```corpus/train.json``` - -* 验证:```corpus/valid.json``` - -* 测试:```corpus/test.json``` - -* 答案:```corpus/answers.json``` -一共有 27,413 个回答,数据格式为 ```json```: ``` -{ - "INDEX": { - "zh": "中文", - "en": "英文" - }, - more ... -} +pip install -r Requirements.txt ``` -### 中英文对照文件 - -#### 问答对 - -``` -格式 INDEX ++$++ 保险种类 ++$++ 中文 ++$++ 英文 -``` - -```corpus/train.txt```, ```corpus/valid.txt```, ```corpus/test.txt```. - -#### 答案 - +## Run +A very simple network as baseline model. ``` -格式 INDEX ++$++ 中文 ++$++ 英文 +python3 deep_qa_1/network.py +python3 visual/accuracy.py +python3 visual/loss.py ``` -```corpus/answers.txt``` - ## 声明 声明1 : [insuranceqa-corpus-zh](https://github.com/Samurais/insuranceqa-corpus-zh) @@ -88,4 +43,4 @@ InsuranceQA Corpus, Hai Liang Wang, https://github.com/Samurais/insuranceqa-corp 声明2 : [insuranceQA](https://github.com/shuzi/insuranceQA) -此数据集仅作为研究目的提供。如果您使用这些数据发表任何内容,请引用我们的论文:[Applying Deep Learning to Answer Selection: A Study and An Open Task](https://arxiv.org/abs/1508.01585)。Minwei Feng, Bing Xiang, Michael R. Glass, Lidan Wang, Bowen Zhou @ 2015 +此数据集仅作为研究目的提供。如果您使用这些数据发表任何内容,请引用我们的论文:[Applying Deep Learning to Answer Selection: A Study and An Open Task](https://arxiv.org/abs/1508.01585)。Minwei Feng, Bing Xiang, Michael R. Glass, Lidan Wang, Bowen Zhou @ 2015 \ No newline at end of file diff --git a/Requirements.txt b/Requirements.txt new file mode 100644 index 0000000..b98fb0a --- /dev/null +++ b/Requirements.txt @@ -0,0 +1,10 @@ +insuranceqa-data==1.3 +matplotlib==2.0.2 +numpy==1.13.1 +pandas==0.20.3 +scikit-learn==0.18.1 +scipy==0.19.1 +six==1.10.0 +virtualenv==15.1.0 +virtualenv-clone==0.2.4 +virtualenvwrapper==4.1.1 \ No newline at end of file diff --git a/deep_qa_1/README.md b/deep_qa_1/README.md new file mode 100644 index 0000000..c50265c --- /dev/null +++ b/deep_qa_1/README.md @@ -0,0 +1,7 @@ +# deep_qa_1 + + +## Test data module +``` +py.test -s -v -f ./deep_qa_1/data.py +``` \ No newline at end of file diff --git a/deep_qa_1/__init__.py b/deep_qa_1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/deep_qa_1/baseline_acc.png b/deep_qa_1/baseline_acc.png new file mode 100644 index 0000000000000000000000000000000000000000..ecf2dc8619c09c2c926f11283911080e1c0d2e0d GIT binary patch literal 24377 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 literal 0 HcmV?d00001 diff --git a/deep_qa_1/baseline_loss.png b/deep_qa_1/baseline_loss.png new file mode 100644 index 0000000000000000000000000000000000000000..6cb148ee1a4073b1784c9c3ef7f4c02092c53e43 GIT binary patch literal 51067 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 z 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 P_>g=i_cT{b_uc;hrv!27 literal 0 HcmV?d00001 diff --git a/deep_qa_1/data.py b/deep_qa_1/data.py new file mode 100755 index 0000000..f10591e --- /dev/null +++ b/deep_qa_1/data.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#=============================================================================== +# +# Copyright (c) 2017 Hai Liang Wang All Rights Reserved +# +# +# File: /Users/hain/ai/InsuranceQA-Machine-Learning/deep_qa_1/network.py +# Author: Hai Liang Wang +# Date: 2017-08-08:18:32:05 +# +#=============================================================================== + +""" + A Simple Network to learning QA. + + +""" +from __future__ import print_function +from __future__ import division + +__copyright__ = "Copyright (c) 2017 Hai Liang Wang. All Rights Reserved" +__author__ = "Hai Liang Wang" +__date__ = "2017-08-08:18:32:05" + + +import os +import sys +curdir = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.dirname(curdir)) + +if sys.version_info[0] < 3: + reload(sys) + sys.setdefaultencoding("utf-8") + # raise "Must be using Python 3" + +import random +import insuranceqa_data as insuranceqa + +_train_data = insuranceqa.load_pairs_train() +_test_data = insuranceqa.load_pairs_test() +_valid_data = insuranceqa.load_pairs_valid() + + +''' +build vocab data with more placeholder +''' +vocab_data = insuranceqa.load_pairs_vocab() +print("keys", vocab_data.keys()) +vocab_size = len(vocab_data['word2id'].keys()) +VOCAB_PAD_ID = vocab_size+1 +VOCAB_GO_ID = vocab_size+2 +vocab_data['word2id'][''] = VOCAB_PAD_ID +vocab_data['word2id'][''] = VOCAB_GO_ID +vocab_data['id2word'][VOCAB_PAD_ID] = '' +vocab_data['id2word'][VOCAB_GO_ID] = '' + + +def _get_corpus_metrics(): + ''' + max length of questions + ''' + for cat, data in zip(["valid", "test", "train"], [_valid_data, _test_data, _train_data]): + max_len_question = 0 + total_len_question = 0 + max_len_utterance = 0 + total_len_utterance = 0 + for x in data: + total_len_question += len(x['question']) + total_len_utterance += len(x['utterance']) + if len(x['question']) > max_len_question: + max_len_question = len(x['question']) + if len(x['utterance']) > max_len_utterance: + max_len_utterance = len(x['utterance']) + print('max len of %s question : %d, average: %d' % (cat, max_len_question, total_len_question/len(data))) + print('max len of %s utterance: %d, average: %d' % (cat, max_len_utterance, total_len_utterance/len(data))) + # max length of answers + + +class BatchIter(): + ''' + Load data with mini-batch + ''' + def __init__(self, data = None, batch_size = 100): + assert data is not None, "data should not be None." + self.batch_size = batch_size + self.data = data + + def next(self): + random.shuffle(self.data) + index = 0 + total_num = len(self.data) + while index <= total_num: + yield self.data[index:index + self.batch_size] + index += self.batch_size + +def padding(lis, pad, size): + ''' + right adjust a list object + ''' + if size > len(lis): + lis += [pad] * (size - len(lis)) + else: + lis = lis[0:size] + return lis + +def pack_question_n_utterance(q, u, q_length = 20, u_length = 99): + ''' + combine question and utterance as input data for feed-forward network + ''' + assert len(q) > 0 and len(u) > 0, "question and utterance must not be empty" + q = padding(q, VOCAB_PAD_ID, q_length) + u = padding(u, VOCAB_PAD_ID, u_length) + assert len(q) == q_length, "question should be pad to q_length" + assert len(u) == u_length, "utterance should be pad to u_length" + return q + [VOCAB_GO_ID] + u + +def __resolve_input_data(data, batch_size, question_max_length = 20, utterance_max_length = 99): + ''' + resolve input data + ''' + batch_iter = BatchIter(data = data, batch_size = batch_size) + + for mini_batch in batch_iter.next(): + result = [] + for o in mini_batch: + x = pack_question_n_utterance(o['question'], o['utterance'], question_max_length, utterance_max_length) + y_ = o['label'] + assert len(x) == utterance_max_length + question_max_length + 1, "Wrong length afer padding" + assert VOCAB_GO_ID in x, " must be in input x" + assert len(y_) == 2, "desired output." + result.append([x, y_]) + if len(result) > 0: + # print('data in batch:%d' % len(mini_batch)) + yield result + else: + raise StopIteration + +# export data + +def load_train(batch_size = 100, question_max_length = 20, utterance_max_length = 99): + ''' + load train data + ''' + return __resolve_input_data(_train_data, batch_size, question_max_length, utterance_max_length) + +def load_test(question_max_length = 20, utterance_max_length = 99): + ''' + load test data + ''' + result = [] + for o in _test_data: + x = pack_question_n_utterance(o['question'], o['utterance'], question_max_length, utterance_max_length) + y_ = o['label'] + assert len(x) == utterance_max_length + question_max_length + 1, "Wrong length afer padding" + assert VOCAB_GO_ID in x, " must be in input x" + assert len(y_) == 2, "desired output." + result.append((x, y_)) + return result + +def load_valid(batch_size = 100, question_max_length = 20, utterance_max_length = 99): + ''' + load valid data + ''' + return __resolve_input_data(_valid_data, batch_size, question_max_length, utterance_max_length) + +def test_batch(): + ''' + retrieve data with mini batch + ''' + for mini_batch in load_test(): + for x, y_ in mini_batch: + print("length", len(x)) + assert len(y_) == 2, "data size should be 2" + + print("VOCAB_PAD_ID", VOCAB_PAD_ID) + print("VOCAB_GO_ID", VOCAB_GO_ID) + +if __name__ == '__main__': + test_batch() + + diff --git a/deep_qa_1/network.py b/deep_qa_1/network.py new file mode 100755 index 0000000..e2f2864 --- /dev/null +++ b/deep_qa_1/network.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#=============================================================================== +# +# Copyright (c) 2012-2015 Michael Nielsen +# Copyright (c) 2017 Hai Liang Wang All Rights Reserved +# +# +# File: /Users/hain/ai/InsuranceQA-Machine-Learning/deep_qa_1/network.py +# Author: Hai Liang Wang +# Date: 2017-08-08:18:32:05 +# +#=============================================================================== + +""" + A Simple Network to learning QA. + + +""" +from __future__ import print_function +from __future__ import division + +__copyright__ = "Copyright (c) 2017 Hai Liang Wang. All Rights Reserved" +__author__ = "Hai Liang Wang" +__date__ = "2017-08-08:18:32:05" + + +import os +import sys +curdir = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.dirname(curdir)) + +import numpy as np +import deep_qa_1.data as corpus +import visual.loss as visual_loss +import visual.accuracy as visual_acc + +if sys.version_info[0] < 3: + reload(sys) + sys.setdefaultencoding("utf-8") + # raise "Must be using Python 3" + +class NeuralNetwork(): + def __init__(self, hidden_layers = [100, 50], + question_max_length = 20, + utterance_max_length = 99, + lr = 0.001, epoch = 10, + batch_size = 100, + eval_every_N_steps = 500): + ''' + Neural Network to train question and answering model + ''' + self.input_layer_size = question_max_length + utterance_max_length + 1 # 1 is for + self.output_layer_size = 2 # just the same shape as labels + self.layers = [self.input_layer_size] + hidden_layers + [self.output_layer_size] # [2] is for output layer + self.layers_num = len(self.layers) + self.weights = [np.random.randn(y, x) for x,y in zip(self.layers[:-1], self.layers[1:])] + self.biases = [np.random.randn(x, 1) for x in self.layers[1:]] + self.epoch = epoch + self.lr = lr + self.batch_size = batch_size + self.eval_every_N_steps = eval_every_N_steps + self.test_data = corpus.load_test() + + def back_propagation(self, x, y_): + ''' + back propagation algorithm to compute the error rates for every W and b + ''' + cost = 0.0 + nabla_b = [np.zeros(b.shape) for b in self.biases] + nabla_w = [np.zeros(w.shape) for w in self.weights] + zs = [] # z vectors + activations = [x] + activation = x + for b, w in zip(self.biases, self.weights): + z = np.dot(w, activation) + b + zs.append(z) + activation = sigmoid(z) + activations.append(activation) + + cost += self.loss_fn(activations[-1], y_) + + # backward + delta = self.loss_fn_derivative(activations[-1], y_) * sigmoid_derivative(zs[-1]) + nabla_b[-1] = delta + nabla_w[-1] = np.dot(delta, activations[-2].transpose()) + + for l in range(2, self.layers_num): + z = zs[-l] + delta = np.dot(self.weights[-l+1].transpose(), delta) * sigmoid_derivative(zs[-l]) + nabla_b[-l] = delta + nabla_w[-l] = np.dot(delta, activations[-l-1].transpose()) + + return (nabla_b, nabla_w, cost) + + def loss_fn(self, a, y_): + # cross-entropy cost fn + return np.sum(np.nan_to_num(-y_*np.log(a) - (1-y_)*np.log(1-a))) + + def loss_fn_derivative(self, a, y_): + # maximum likelihood estimation + return (a-y_) + + def run(self, test = False): + ''' + Train model with mini-batch stochastic gradient descent. + ''' + total_step = 0 + for n in range(self.epoch): + for mini_batch in corpus.load_train(): + nabla_b = [np.zeros(b.shape) for b in self.biases] + nabla_w = [np.zeros(w.shape) for w in self.weights] + total_cost = 0.0 + for x, y_ in mini_batch: + # here scale the input's word ids with 0.001 for x to make sure the Z-vector can pass sigmoid fn + delta_nabla_b, delta_nabla_w, cost = self.back_propagation( \ + np.reshape(x, (self.input_layer_size, 1)) * 0.001, \ + np.reshape(y_, (self.output_layer_size, 1))) + nabla_b = [ nb+mnb for nb, mnb in zip(nabla_b, delta_nabla_b)] + nabla_w = [ nw+mnw for nw, mnw in zip(nabla_w, delta_nabla_w)] + total_cost += cost + self.weights = [ w - (self.lr * w_)/len(mini_batch) for w, w_ in zip(self.weights, nabla_w)] + self.biases = [ b - (self.lr * b_)/len(mini_batch) for b, b_ in zip(self.biases, nabla_b)] + total_step += 1 + print("Epoch %s, total step %d, cost %f" % (n, total_step, total_cost/len(mini_batch))) + visual_loss.plot(total_step, total_cost/len(mini_batch)) + if (total_step % self.eval_every_N_steps ) == 0 and test: + accuracy = self.evaluate() + print("Epoch %s, total step %d, accuracy %s" % (n, total_step, accuracy)) + visual_acc.plot(total_step, accuracy) + + def feedforward(self, x): + ''' + Feedforward network + ''' + activation = x + for w, b in zip(self.weights, self.biases): + z = np.dot(w, activation) + b + activation = sigmoid(z) + return activation + + def evaluate(self): + ''' + evaluate model + ''' + # for (x,y) in self.test_data: + # r = self.feedforward(np.reshape(x, (self.input_layer_size, 1)) * 0.001) + # print("feedforward", r) + # print("argmax", np.argmax(r)) + # print("y", y) + # print("*"*20) + result = [(np.argmax(self.feedforward(np.reshape(x, (self.input_layer_size, 1)) * 0.001)), y) for (x, y) in self.test_data] + # print(result) + print("count", sum(int(y[x] == 1) for (x, y) in result)) + return "%.4f" % ( sum(int(y[x] == 1) for (x, y) in result)/ len(self.test_data)) + +def sigmoid(x): + return 1.0 / (1.0 + np.exp(-x)) + +def sigmoid_derivative(x): + return sigmoid(x) * ( 1.0 - sigmoid(x)) + +def test_train(): + visual_loss.init() + visual_acc.init() + nn = NeuralNetwork(epoch = 50, lr = 0.0001, eval_every_N_steps = 200) + nn.run(test = True) + +if __name__ == '__main__': + test_train() diff --git a/tmp/.gitignore b/tmp/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/tmp/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/visual/__init__.py b/visual/__init__.py new file mode 100755 index 0000000..e69de29 diff --git a/visual/accuracy.py b/visual/accuracy.py new file mode 100755 index 0000000..cd244a0 --- /dev/null +++ b/visual/accuracy.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#=============================================================================== +# +# Copyright (c) 2017 <> All Rights Reserved +# +# +# File: /Users/hain/ai/InsuranceQA-Machine-Learning/deep_qa_1/visual.py +# Author: Hai Liang Wang +# Date: 2017-08-09:21:56:58 +# +#=============================================================================== + +""" + +""" +from __future__ import print_function +from __future__ import division + +__copyright__ = "Copyright (c) 2017 . All Rights Reserved" +__author__ = "Hai Liang Wang" +__date__ = "2017-08-09:21:56:58" + +import os +import sys +curdir = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.dirname(curdir)) + +if sys.version_info[0] < 3: + reload(sys) + sys.setdefaultencoding("utf-8") + # raise "Must be using Python 3" + +import csv +import numpy as np +from statsmodels.nonparametric.smoothers_lowess import lowess +import matplotlib.pyplot as plt +import matplotlib.animation as animation +from matplotlib import style + +# style.use('fivethirtyeight') +style.use(["ggplot", os.path.join(curdir, "tensorflowvisu.mplstyle")]) +fig = plt.figure() +ax = fig.add_subplot(111) +graph_data_f = os.path.join(curdir, '..', 'tmp', 'accuracy.txt') + +def init(): + with open(graph_data_f, "w") as f: + f.write('') + +def plot(step, accuracy): + with open(graph_data_f, "a") as f: + f.write('%s\t%s\n' % (step, accuracy)) + +def animate(i): + graph_data = np.loadtxt(graph_data_f, skiprows=0, delimiter='\t', unpack=True).transpose() + steps = graph_data[:,0] + accuracy = graph_data[:,1] + # filtered = lowess(accuracy, steps, is_sorted=True, frac=148.0/len(steps), it=0) + ax.clear() + ax.set_xlabel('steps') + ax.set_ylabel('accuracy') + ax.plot(steps, accuracy, 'r') + # ax.plot(filtered[:,0], filtered[:,1], 'b') + +def test_draw(): + ani = animation.FuncAnimation(fig, animate, interval=3000) + plt.show() + +if __name__ == '__main__': + test_draw() diff --git a/visual/loss.py b/visual/loss.py new file mode 100755 index 0000000..f54f24e --- /dev/null +++ b/visual/loss.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +#=============================================================================== +# +# Copyright (c) 2017 <> All Rights Reserved +# +# +# File: /Users/hain/ai/InsuranceQA-Machine-Learning/deep_qa_1/visual.py +# Author: Hai Liang Wang +# Date: 2017-08-09:21:56:58 +# +#=============================================================================== + +""" + +""" +from __future__ import print_function +from __future__ import division + +__copyright__ = "Copyright (c) 2017 . All Rights Reserved" +__author__ = "Hai Liang Wang" +__date__ = "2017-08-09:21:56:58" + +import os +import sys +curdir = os.path.dirname(os.path.abspath(__file__)) +sys.path.insert(0, os.path.dirname(curdir)) + +if sys.version_info[0] < 3: + reload(sys) + sys.setdefaultencoding("utf-8") + # raise "Must be using Python 3" + +import csv +import numpy as np +from statsmodels.nonparametric.smoothers_lowess import lowess +import matplotlib.pyplot as plt +import matplotlib.animation as animation +from matplotlib import style + +# style.use('fivethirtyeight') +style.use(["ggplot", os.path.join(curdir, "tensorflowvisu.mplstyle")]) +fig = plt.figure() +ax = fig.add_subplot(111) + +graph_data_f = os.path.join(curdir, '..', 'tmp', 'loss.txt') + +def init(): + with open(graph_data_f, "w") as f: + f.write('') + +def plot(step, loss): + with open(graph_data_f, "a") as f: + f.write('%s\t%s\n' % (step, loss)) + +def animate(i): + graph_data = np.loadtxt(graph_data_f, skiprows=0, delimiter='\t', unpack=True).transpose() + steps = graph_data[:,0] + loss = graph_data[:,1] + filtered = lowess(loss, steps, is_sorted=True, frac=148.0/len(steps), it=0) + ax.clear() + ax.set_xlabel('steps') + ax.set_ylabel('loss') + ax.plot(steps, loss, 'r') + ax.plot(filtered[:,0], filtered[:,1], 'b') + +def test_draw(): + ani = animation.FuncAnimation(fig, animate, interval=3000) + plt.show() + +if __name__ == '__main__': + test_draw() diff --git a/visual/tensorflowvisu.mplstyle b/visual/tensorflowvisu.mplstyle new file mode 100644 index 0000000..aa2bcf5 --- /dev/null +++ b/visual/tensorflowvisu.mplstyle @@ -0,0 +1,55 @@ +# encoding: UTF-8 +# Copyright 2016 Google.com +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +text.color: 555555 + +legend.fancybox: true +legend.framealpha: 0.4 +legend.facecolor: white +legend.edgecolor: white + +patch.facecolor: FF3333 + +# good for 1080p output +figure.subplot.left: 0.11 +figure.subplot.right: 0.89 +figure.subplot.bottom: 0.15 +figure.subplot.top: 0.93 +figure.subplot.wspace: 0.3 +figure.subplot.hspace: 0.2 +axes.titlesize: xx-large +xtick.labelsize: x-large +ytick.labelsize: x-large +legend.fontsize: x-large +axes.prop_cycle: cycler('color', ['4444FF', 'FF3333', '22AA22']) + cycler('linewidth',[1, 3, 1]) + +xtick.major.size: 0 +ytick.major.size: 0 +xtick.major.pad: 5 +ytick.major.pad: 5 + +# alt settings for for 1300x800 screen output +#figure.subplot.left: 0.07 +#figure.subplot.right: 0.93 +#figure.subplot.bottom: 0.07 +#figure.subplot.top: 0.93 +#figure.subplot.wspace: 0.2 +#figure.subplot.hspace: 0.2 +#axes.titlesize: large +#xtick.labelsize: medium +#ytick.labelsize: medium +#legend.fontsize: medium +#axes.prop_cycle: cycler('color', ['4444FF', 'FF3333', '22AA22']) + cycler('linewidth',[0.7, 2, 0.7]) +