visualDL 6.0 KB
Newer Older
Q
qiaolongfei 已提交
1
#!/user/bin/env python
Y
Yan Chunwei 已提交
2

Q
Qiao Longfei 已提交
3 4
import json
import os
5 6
import exceptions
import time
Q
Qiao Longfei 已提交
7 8 9
import sys
from optparse import OptionParser

S
superjom 已提交
10 11
from flask import (Flask, Response, redirect, request, send_file,
                   send_from_directory)
Q
Qiao Longfei 已提交
12

Y
Yan Chunwei 已提交
13
import visualdl
Y
Yan Chunwei 已提交
14
import visualdl.server
15 16
import visualdl.server.graph as vdl_graph
from visualdl.server import lib
Q
qiaolongfei 已提交
17
from visualdl.server.log import logger
Y
Yan Chunwei 已提交
18 19 20
from visualdl.server.mock import data as mock_data
from visualdl.server.mock import data as mock_tags
from visualdl.python.storage import (LogWriter, LogReader)
Q
Qiao Longfei 已提交
21 22

app = Flask(__name__, static_url_path="")
S
superjom 已提交
23 24
# set static expires in a short time to reduce browser's memory usage.
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 30
Q
Qiao Longfei 已提交
25

26 27 28
error_retry_times = 3
error_sleep_time = 2  # seconds

Y
Yan Chunwei 已提交
29
SERVER_DIR = os.path.join(visualdl.ROOT, 'server')
Q
Qiao Longfei 已提交
30

Y
Yan Chunwei 已提交
31

32 33 34 35 36 37 38 39
def try_call(function, *args, **kwargs):
    res = lib.retry(error_retry_times, function, error_sleep_time, *args,
                    **kwargs)
    if not res:
        raise exceptions.IOError("server IO error, will retry latter.")
    return res


Q
Qiao Longfei 已提交
40 41 42 43
def option_parser():
    """
    :return:
    """
Y
Yan Chunwei 已提交
44
    parser = OptionParser(usage="usage: visualDL -p port [options]")
Q
Qiao Longfei 已提交
45 46 47
    parser.add_option(
        "-p",
        "--port",
Q
Qiao Longfei 已提交
48
        type=int,
Q
Qiao Longfei 已提交
49 50 51
        default=8040,
        action="store",
        dest="port",
S
debug  
superjom 已提交
52 53 54 55 56 57 58 59
        help="api service port")
    parser.add_option(
        "-t",
        "--host",
        type=str,
        default="0.0.0.0",
        action="store",
        help="api service ip")
Y
Yan Chunwei 已提交
60 61 62 63 64 65
    parser.add_option(
        "-m",
        "--model_pb",
        type=str,
        action="store",
        help="model proto in ONNX format")
Q
Qiao Longfei 已提交
66 67 68 69 70 71 72
    parser.add_option(
        "--logdir", action="store", dest="logdir", help="log file directory")
    return parser.parse_args()


options, args = option_parser()
server_path = os.path.abspath(os.path.dirname(sys.argv[0]))
Y
Yan Chunwei 已提交
73 74
static_file_path = os.path.join(SERVER_DIR, "./dist")
mock_data_path = os.path.join(SERVER_DIR, "./mock_data/")
Q
Qiao Longfei 已提交
75

Y
Yan Chunwei 已提交
76
log_reader = LogReader(options.logdir)
S
debug  
superjom 已提交
77

Y
Yan Chunwei 已提交
78
graph_image_path = None
Q
Qiao Longfei 已提交
79

80

Q
Qiao Longfei 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
# return data
# status, msg, data
def gen_result(status, msg, data):
    """
    :param status:
    :param msg:
    :return:
    """
    result = dict()
    result['status'] = status
    result['msg'] = msg
    result['data'] = data
    return result


@app.route("/")
def index():
    return redirect('/static/index.html', code=302)


@app.route('/static/<path:filename>')
def serve_static(filename):
Y
Yan Chunwei 已提交
103
    print 'serve static ', filename
Q
Qiao Longfei 已提交
104 105 106
    return send_from_directory(
        os.path.join(server_path, static_file_path), filename)

107

Y
Yan Chunwei 已提交
108 109 110
@app.route('/graphs/image')
def serve_graph():
    return send_file(graph_image_path)
Q
Qiao Longfei 已提交
111

112

Q
Qiao Longfei 已提交
113 114 115 116 117 118 119 120
@app.route('/data/logdir')
def logdir():
    result = gen_result(0, "", {"logdir": options.logdir})
    return Response(json.dumps(result), mimetype='application/json')


@app.route('/data/runs')
def runs():
121
    result = gen_result(0, "", lib.get_modes(log_reader))
Q
Qiao Longfei 已提交
122 123 124 125
    return Response(json.dumps(result), mimetype='application/json')


@app.route("/data/plugin/scalars/tags")
S
superjom 已提交
126 127
def scalar_tags():
    mode = request.args.get('mode')
Q
Qiao Longfei 已提交
128
    is_debug = bool(request.args.get('debug'))
129
    result = try_call(lib.get_scalar_tags, log_reader)
S
superjom 已提交
130 131 132 133 134
    result = gen_result(0, "", result)
    return Response(json.dumps(result), mimetype='application/json')


@app.route("/data/plugin/images/tags")
S
superjom 已提交
135
def image_tags():
S
superjom 已提交
136
    mode = request.args.get('run')
137
    result = try_call(lib.get_image_tags, log_reader)
138 139 140 141 142 143 144
    result = gen_result(0, "", result)
    return Response(json.dumps(result), mimetype='application/json')


@app.route("/data/plugin/histograms/tags")
def histogram_tags():
    mode = request.args.get('run')
145 146
    # hack to avlid IO conflicts
    result = try_call(lib.get_histogram_tags, log_reader)
S
debug  
superjom 已提交
147
    result = gen_result(0, "", result)
Q
Qiao Longfei 已提交
148 149 150 151 152 153 154
    return Response(json.dumps(result), mimetype='application/json')


@app.route('/data/plugin/scalars/scalars')
def scalars():
    run = request.args.get('run')
    tag = request.args.get('tag')
155
    result = try_call(lib.get_scalar, log_reader, run, tag)
S
superjom 已提交
156
    result = gen_result(0, "", result)
Q
Qiao Longfei 已提交
157 158 159
    return Response(json.dumps(result), mimetype='application/json')


S
superjom 已提交
160 161
@app.route('/data/plugin/images/images')
def images():
S
superjom 已提交
162
    mode = request.args.get('run')
S
superjom 已提交
163
    tag = request.args.get('tag')
S
superjom 已提交
164

165
    result = try_call(lib.get_image_tag_steps, log_reader, mode, tag)
S
superjom 已提交
166
    result = gen_result(0, "", result)
S
superjom 已提交
167 168 169 170 171 172

    return Response(json.dumps(result), mimetype='application/json')


@app.route('/data/plugin/images/individualImage')
def individual_image():
S
superjom 已提交
173
    mode = request.args.get('run')
S
superjom 已提交
174
    tag = request.args.get('tag')  # include a index
S
superjom 已提交
175
    step_index = int(request.args.get('index'))  # index of step
S
superjom 已提交
176 177
    offset = 0

178 179
    imagefile = try_call(lib.get_invididual_image, log_reader, mode, tag,
                         step_index)
S
superjom 已提交
180 181 182 183
    response = send_file(
        imagefile, as_attachment=True, attachment_filename='img.png')
    return response

S
superjom 已提交
184

185 186 187 188
@app.route('/data/plugin/histograms/histograms')
def histogram():
    run = request.args.get('run')
    tag = request.args.get('tag')
189
    result = try_call(lib.get_histogram, log_reader, run, tag)
190 191 192 193
    result = gen_result(0, "", result)
    return Response(json.dumps(result), mimetype='application/json')


Y
Yan Chunwei 已提交
194
@app.route('/data/plugin/graphs/graph')
Q
qiaolongfei 已提交
195
def graph():
Y
Yan Chunwei 已提交
196
    # TODO(ChunweiYan) need to add a config for whether have graph.
Q
Qiao Longfei 已提交
197 198 199 200
    if graph_image_path is None:
        data = {'url': ''}
    else:
        data = {'url': '/graphs/image'}
Y
Yan Chunwei 已提交
201
    result = gen_result(0, "", data)
Q
Qiao Longfei 已提交
202
    return Response(json.dumps(result), mimetype='application/json')
Q
qiaolongfei 已提交
203

S
superjom 已提交
204

Q
Qiao Longfei 已提交
205 206
if __name__ == '__main__':
    logger.info(" port=" + str(options.port))
Y
Yan Chunwei 已提交
207 208 209 210
    if not options.logdir:
        logger.error("should pass in logdir option")
        sys.exit(-1)

Y
Yan Chunwei 已提交
211 212 213 214 215 216
    if options.model_pb:
        # draw graph
        image_dir = os.path.join(options.logdir, "graphs")
        if not os.path.isdir(image_dir):
            os.mkdir(image_dir)
        graph_image_path = vdl_graph.draw_graph(options.model_pb, image_dir)
Y
Yan Chunwei 已提交
217

S
superjom 已提交
218
    app.run(debug=False, host=options.host, port=options.port)