Reputation: 2287
I am creating a web application with Django (back end) and JavaScript (front end).
The main scenario is the following: a client asks the server to train a neural network (which can take quite a lot: seconds or even minutes, sometimes). Immediately after sending the request, the client shows to the user how the training session is going; it does so by retrieving and displaying the training error, which is actually just a number.
For training the network I made this function, which I implemented as a generator:
def train(network, trainset):
# [setup variables...]
while (current_error > target_error):
# [continue to train the network...]
# [update current_error...]
yield current_error
On the front end (a simple HTML page) I have a JS script for retrieving data dynamically from a Django view. My Django view goes something like this:
def getError(request):
# ...
generator = train(net, dataset)
return StreamingHttpResponse(generator)
At the moment I can retrieve the data with an AJAX call but I always have to wait for the server to train the whole neural network before I can see the training errors.
My problem is that I would like the user to view the error updates while the server is training the network, not after: that's why I implemented the training function as a generator (and that's why I chose to return a StreamingHttpResponse
).
What can I do for retrieving the data while the server is computing? Specifically, I would like to update the front end each time the training generator yield
s a number.
Upvotes: 1
Views: 644
Reputation: 23134
Initial analysis:
Let's have a look at the documentation:
The yield expression is used when defining a generator function
A function which returns a generator iterator. It looks like a normal function except that it contains yield expressions for producing a series of values usable in a for-loop or that can be retrieved one at a time with the next() function.
From the aforementioned it is clear that your code sample works well but not as intended:
The train()
function yields
a generator
which gets "transmitted" to your front-end from the getError
after the whole calculation is done.
With the above mentioned, your problem will be to get the calculations of each step of the train()
process and display them to the front-end.
Refactor train()
function to use the previous list:
train_errors = []
def train(network, trainset):
# [setup variables...]
while (current_error > target_error):
# [continue to train the network...]
# [update current_error...]
train_errors.append(current_error)
Assuming that train()
is located in views.py
file, refactor the getError()
to return the train_errors
list:
from django.http import JsonResponse
def getError(request):
# ...
return JsonResponse(train_errors, safe=False)
I utilize JsonResponse, but feel free to use anything that suites you.
Make your front-end to repeat the AJAX call every N seconds, by utilizing javascript's setInterval
, and display the differences from the previous state of the data.
Example of use:
var myIntervalCall = setInterval(myAJAXcall, 500);
function myAJAXcall{
// Create your AJAX call in here
// And sufficient code to display the changes on the received data.
}
The above code will make myAJAXcall
to the back-end, every 0.5 sec
The above will allow you to make an initial approach to your problem and you can/must expand on this (barbaric) solution.
The above, is not a good solution!! It is only a quick solution to get the author "unstuck" from his current problem and help him move on with his development.
The "solution" provides the basis for a thought process, considering the problem at hand (the actual problem that the author has at the moment) and therefore provides a minimal and initial approach to a solution.
The aforementioned distiled: DO NOT TAKE THIS SOLUTION AS CANON! it is only a "jump start".
Upvotes: 2
Reputation: 77912
Solution 1: use celery for the computation, storing progress in redis, and have your front side js code poll a view that will get progress from a dedicated view.
Solution 2: use a websocket.
Upvotes: 1