<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: aishahsofea</title>
    <description>The latest articles on DEV Community by aishahsofea (@aishahsofea).</description>
    <link>https://dev.to/aishahsofea</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F385201%2Fa30f9ff9-4209-44b6-939c-85fb5a55d6b0.jpeg</url>
      <title>DEV Community: aishahsofea</title>
      <link>https://dev.to/aishahsofea</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aishahsofea"/>
    <language>en</language>
    <item>
      <title>Dynamically change scheduled tasks with Django &amp; celery beat</title>
      <dc:creator>aishahsofea</dc:creator>
      <pubDate>Fri, 17 Sep 2021 15:49:30 +0000</pubDate>
      <link>https://dev.to/aishahsofea/dynamically-change-beat-schedule-with-djangocelerybeat-2aia</link>
      <guid>https://dev.to/aishahsofea/dynamically-change-beat-schedule-with-djangocelerybeat-2aia</guid>
      <description>&lt;h4&gt;
  
  
  Background
&lt;/h4&gt;

&lt;p&gt;I was trying to create something similar to CoinGecko/CoinMarketCap where a list of coins with its current price will be displayed. In the first iteration, I fetched the current price via an HTTP request, and while this works, it is not the best and can be rather inconvenient. Cryptocurrency is known for its volatility, so if the user stays idle for a couple of minutes, the price displayed will quickly be outdated. They can only get the updated price after refreshing the page. On average, the API call takes around 600 to 1000ms. Imagine having to wait 1 second every time you want to get an updated Bitcoin price on top of having to refresh the page. That's pretty annoying, isn't it? So how do we go about solving this? Let's dive right in.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tech stack
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Django&lt;/strong&gt; as the web framework&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; for the UI stuff (the bulk of this article will be on the BE so it's totally fine if you don't know React)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Celery&lt;/strong&gt; for asynchronous task execution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Channels&lt;/strong&gt; to allow WebSocket communication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis&lt;/strong&gt; as the message queue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: If you are on Windows, chances are you'll encounter an issue when running Celery since it does not officially support Windows. So I highly recommend you to use WSL instead. It is also easier to install Redis on WSL.&lt;/p&gt;

&lt;p&gt;Also note: This tutorial assumes that you already have some experience with Django.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setup and installation
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Set up Django and React boilerplate.
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;Create a folder for our project, let's call it &lt;code&gt;cmc_clone&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Assuming you already have Python installed, create a virtual environment inside cmc_clone; &lt;code&gt;python3 -m venv venv&lt;/code&gt;. Note that I use &lt;code&gt;python3&lt;/code&gt;, that's because I have both Python 2 &amp;amp; 3 installed on my WSL.&lt;/li&gt;
&lt;li&gt;Now you'll see &lt;code&gt;venv&lt;/code&gt; folder inside your directory. Activate the virtual env like so; &lt;code&gt;source venv/bin/activate&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Now let's install Django; &lt;code&gt;pip install django&lt;/code&gt;. Run &lt;code&gt;pip freeze | grep Django&lt;/code&gt; or simply &lt;code&gt;python -m django --version&lt;/code&gt; to ensure that it's been installed. (Note that I'm now using &lt;code&gt;python&lt;/code&gt; instead of &lt;code&gt;python3&lt;/code&gt; since I'm already inside the virtual environment)&lt;/li&gt;
&lt;li&gt;Once Django has been successfully installed, let's start a Django project called server; &lt;code&gt;django-admin startproject server&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;Inside server folder, you will see another &lt;code&gt;server&lt;/code&gt; folder and &lt;code&gt;manage.py&lt;/code&gt; file. This is the boilerplate that Django automagically creates for us. To make sure that it is indeed working, run &lt;code&gt;python manage.py runserver&lt;/code&gt; and go to &lt;code&gt;localhost:8000&lt;/code&gt; on your browser. You should see a rocket animation and that means your Django server is properly running. &lt;/li&gt;
&lt;li&gt;Cool, now let's create an app called coin; &lt;code&gt;python manage.py startapp coin&lt;/code&gt; on the same level as &lt;code&gt;manage.py&lt;/code&gt; file. You will see a &lt;code&gt;coin&lt;/code&gt; folder being created, this is what we'll use later for our logic. Make sure to include it under &lt;code&gt;INSTALLED_APPS&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Let's move on to React. For this we will also use a boilerplate from &lt;code&gt;create-react-app&lt;/code&gt;. Assuming you have npm installed, let's generate React boilerplate inside cmc_clone folder (same level as venv folder); &lt;code&gt;npx create-react-app client&lt;/code&gt;.  This might take a few minutes.&lt;/li&gt;
&lt;li&gt;Go inside client folder and run &lt;code&gt;npm start&lt;/code&gt;. A development server will run at &lt;code&gt;localhost:3000&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  Install Redis and make sure it is properly working.
&lt;/h5&gt;

&lt;ol&gt;
&lt;li&gt;Follow this &lt;a href="https://www.youtube.com/watch?v=_nFwPTHOMIY"&gt;tutorial&lt;/a&gt; for Windows 10.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I will structure this article in the sequence of the mistakes that I made. So bear with me. &lt;/p&gt;

&lt;h4&gt;
  
  
  Getting current price of the coins without the hassle of refreshing the page
&lt;/h4&gt;

&lt;p&gt;So the first problem that we want to solve is getting the updated coin price without having to refresh the page. This is where WebSocket comes in. Unlike HTTP where client needs to send a request each time they want to get a response, WebSocket makes sure that the connection between a client and a server stays open. &lt;/p&gt;

&lt;p&gt;As for the coin data, we will use &lt;a href="https://www.coingecko.com/en/api/documentation"&gt;CoinGecko API&lt;/a&gt;. There is a bunch of endpoints that you can leverage but for our purpose we are only interested to use the &lt;code&gt;/coin/markets&lt;/code&gt; endpoint. &lt;/p&gt;

&lt;p&gt;Let's say we want to get the a price every 30 seconds. Since we don't want to refresh the page, there should be a background process that does this for us, something similar to cron job. Luckily, Celery is pretty good at this.&lt;/p&gt;

&lt;p&gt;So there are 2 main parts here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up a WebSocket connection &lt;/li&gt;
&lt;li&gt;Execute background tasks&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Setting up a WebSocket connection
&lt;/h4&gt;

&lt;p&gt;For this we will use a package called channels. Follow the official &lt;a href="https://channels.readthedocs.io/en/stable/installation.html"&gt;installation guide&lt;/a&gt;. &lt;br&gt;
Make sure you include &lt;code&gt;channels&lt;/code&gt; in the &lt;code&gt;INSTALLED_APPS&lt;/code&gt; inside &lt;code&gt;settings.py&lt;/code&gt;. Also, under WSGI settings, please add this line &lt;code&gt;ASGI_APPLICATION = 'server.asgi.application'&lt;/code&gt;.&lt;br&gt;
If you encounter any error, please consider upgrading pip. &lt;/p&gt;

&lt;p&gt;Then, install the channels_redis package; &lt;code&gt;pip install channels-redis&lt;/code&gt;. lt provides channel layers that use Redis. Visit the &lt;a href="https://github.com/django/channels_redis"&gt;Github&lt;/a&gt; for more config options.&lt;br&gt;
But for us, we will use the following. Include this inside &lt;code&gt;settings.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CHANNEL_LAYERS = {
        'default': {
            'BACKEND': 'channels_redis.core.RedisChannelLayer',
            'CONFIG': {
                'hosts': [('127.0.0.1', 6379)]
            }
        }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now modify &lt;code&gt;asgi.py&lt;/code&gt; so it can handle WebSocket communication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from coin.routing import ws_urlpatterns
from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'core.settings')

application = ProtocolTypeRouter({
    'http': get_asgi_application(),
    'websocket': AuthMiddlewareStack(URLRouter(ws_urlpatterns))
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have yet to create the &lt;code&gt;ws_urlpatterns&lt;/code&gt;, so don't worry about that for now.&lt;/p&gt;

&lt;p&gt;Inside  &lt;code&gt;coin&lt;/code&gt; folder, create &lt;code&gt;consumers.py&lt;/code&gt; and &lt;code&gt;routing.py&lt;/code&gt;. You can think of &lt;code&gt;consumers.py&lt;/code&gt; to asgi application as &lt;code&gt;views.py&lt;/code&gt; is to normal Django application, which also has its own routing. &lt;/p&gt;

&lt;p&gt;Let's deal with consumers first. Paste the following code inside &lt;code&gt;consumers.py&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json

from channels.generic.websocket import AsyncWebsocketConsumer

class CoinListConsumer(AsyncWebsocketConsumer):

    async def connect(self):
        await self.channel_layer.group_add('coin_list', self.channel_name)
        await self.accept()
        await self.send(json.dumps({'message': 'hey im server'}))

    def receive(self, text_data):
        print(text_data)

    async def disconnect(self):
        await self.channel_layer.group_discard('coin_list', self.channel_name)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I'm writing the consumer class as asynchronous by extending &lt;code&gt;AsyncWebsocketConsumer&lt;/code&gt; class provided by channels. To understand consumers better, do read the &lt;a href="https://channels.readthedocs.io/en/stable/topics/consumers.html"&gt;doc&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now let's create the route for our &lt;code&gt;CoinListConsumer&lt;/code&gt;. Inside &lt;code&gt;routing.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path

from .consumers import CoinListConsumer

ws_urlpatterns = [
    path('ws/coin_list/', CoinListConsumer.as_asgi())
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the &lt;code&gt;ws_urlpatterns&lt;/code&gt; is the one that we imported inside &lt;code&gt;asgi.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, let's connect to the WebSocket from the client. Inside &lt;code&gt;/client/src&lt;/code&gt; folder, modify &lt;code&gt;App.js&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const socket = new WebSocket("ws://localhost:8000/coin_list/");

function App() {

    useEffect(() =&amp;gt; {
        socket.onmessage = (message) =&amp;gt; {
            const data = JSON.parse(message.data);
            console.log(data);
        };
    }, []);

    const handleButtonClick = () =&amp;gt; {
        socket.send(
            JSON.stringify({
                message: "hey im client",
            })
        );
    };

    return (
        &amp;lt;div  className="App"&amp;gt;
            &amp;lt;button  onClick={handleButtonClick}&amp;gt;Send message to the server&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}

export  default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you should see a button on React server.&lt;br&gt;
Restart Django server, and you'll see an additional line saying something like &lt;code&gt;Starting ASGI/Channels version 3.0.4 development server at http://127.0.0.1:8000/&lt;/code&gt;. This means that our ASGI is properly configured and the client can now talk to our server via WebSocket. &lt;/p&gt;

&lt;p&gt;Open console tab on your browser, and refresh the page. You should see: &lt;code&gt;{ "message": "hey im server" }&lt;/code&gt;. It's a JSON that we send from the consumer inside &lt;code&gt;connect()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Try clicking on the button and monitor the Django terminal. You should see something like below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OeZw1btE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gf9pgh3dowowyfm6whwe.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OeZw1btE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gf9pgh3dowowyfm6whwe.PNG" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
It's the message that we send from the client using &lt;code&gt;socket.send()&lt;/code&gt; method, and received by the consumer as a &lt;code&gt;text_data&lt;/code&gt; in the &lt;code&gt;receive()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;Great, WebSocket is working. Let's make it more exciting by integrating Celery beat.&lt;/p&gt;
&lt;h4&gt;
  
  
  Execute scheduled background tasks with Celery beat
&lt;/h4&gt;

&lt;p&gt;First, we'll install Celery. In our case the background task that we want to execute is the API call and we'd like to use Redis for our message broker. So make sure to also install all the required packages; &lt;code&gt;pip install celery requests redis&lt;/code&gt;&lt;br&gt;
On the same level as &lt;code&gt;settings.py&lt;/code&gt;, create a file called &lt;code&gt;celery.py&lt;/code&gt;. This is where we will configure Celery. You can visit this &lt;a href="https://docs.celeryproject.org/en/stable/django/first-steps-with-django.html#using-celery-with-django"&gt;link&lt;/a&gt; for the explanation on the configuration. Inside &lt;code&gt;celery.py&lt;/code&gt;, paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import os

from celery import Celery

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings')

app = Celery('server')

app.config_from_object('django.conf:settings', namespace='CELERY')

app.autodiscover_tasks()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, make sure to import the app inside &lt;code&gt;__init__.py&lt;/code&gt;. Next, create &lt;code&gt;tasks.py&lt;/code&gt; and paste the code below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import requests
from asgiref.sync import async_to_sync
from celery import shared_task
from channels.layers import get_channel_layer

channel_layer = get_channel_layer()

def get_market_api(page=1, per_page=100, currency='usd'):
    market_api = f'https://api.coingecko.com/api/v3/coins/markets?vs_currency={currency}&amp;amp;page={page}&amp;amp;per_page={per_page}'
    return market_api

@shared_task
def get_coin_list():
    data = requests.get(get_market_api(1, 100, 'usd')).json()

    async_to_sync(channel_layer.group_send)(
        'coin_list', {
            'type': 'send_coin_list',
            'coin_list': data
    }
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;get_coin_list()&lt;/code&gt; is where we do the API call, and since we want to schedule this task, we're using the &lt;code&gt;shared_task&lt;/code&gt; decorator so that it can be used anywhere in the project. Note that we use &lt;code&gt;async_to_sync()&lt;/code&gt; function, and this is because &lt;code&gt;get_coin_list()&lt;/code&gt; is a synchronous function but we would like to send the data to an asynchronous function inside consumers; &lt;code&gt;send_coin_list()&lt;/code&gt;. Speaking of which, we haven't actually created the said function. Inside the &lt;code&gt;CoinListConsumer&lt;/code&gt; class, just add the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async def send_coin_list(self, event):
    coin_list = event['coin_list']
    await self.send(json.dumps(coin_list))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remember that we want to schedule the API call so that it will be executed every 30 seconds. Inside &lt;code&gt;celery.py&lt;/code&gt;, add the following code right before &lt;code&gt;app.autodiscover_tasks()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.conf.beat_schedule = {
    'get_coin_list_30s': {
        'task': 'coin.tasks.get_coin_list',
        'schedule': 30.0
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want to use Redis as our message broker, so add the following inside &lt;code&gt;settings.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CELERY_BROKER_URL = 'redis://localhost:6379'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Before integrating with the front-end, let's make sure the scheduler is actually working. Open new terminals and activate the same python virtual environment. Inside the first terminal, run &lt;code&gt;celery -A server beat -l INFO&lt;/code&gt; and in the second one, run &lt;code&gt;celery -A server worker -l INFO --pool=solo&lt;/code&gt;. If you're on linux you may omit the pool argument. Once celery beat has started, take note of the configuration, right now it is using PersistentScheduler as the scheduler. This information will be useful later.&lt;/p&gt;

&lt;p&gt;So what is happening here is that celery beat will send the task to Redis message broker every 30 seconds, and celery worker will check the queue and execute the first item in it.&lt;br&gt;
The beat terminal should look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2021-09-17 15:34:04,540: INFO/MainProcess] Scheduler: Sending due task get_coin_list_30s (coin.tasks.get_coin_list)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and worker terminal should look as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[2021-09-17 15:34:06,041: INFO/MainProcess] celery@aishahsofea ready.
[2021-09-17 15:34:06,051: INFO/MainProcess] Task coin.tasks.get_coin_list[e211f23a-63a3-498d-9068-845beaf6c0e1] received
[2021-09-17 15:34:07,676: INFO/MainProcess] Task coin.tasks.get_coin_list[e211f23a-63a3-498d-9068-845beaf6c0e1] succeeded in 1.6234161000029417s: None
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's display the scheduled data in the UI. Modify App.js as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { useEffect, useState } from  "react";

const socket = new WebSocket("ws://localhost:8000/coin_list/");

    function App() {
    const [coins, setCoins] = useState([]);

    useEffect(() =&amp;gt; {
        socket.onmessage = (message) =&amp;gt; {
            const data = JSON.parse(message.data);
            setCoins(data["coin_list"]);
        };
    }, []);

    return (
        &amp;lt;div  className="App"&amp;gt;
            &amp;lt;ol&amp;gt;
                {coins
                    ? coins.map((coin) =&amp;gt; (
                        &amp;lt;li&amp;gt;
                            {coin.name} | {coin.current_price} USD
                        &amp;lt;/li&amp;gt;
                    ))
                : null}
            &amp;lt;/ol&amp;gt;
        &amp;lt;/div&amp;gt;
    );
}

export  default App;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A list of coins will be displayed along with their price, and at least every 30 seconds the price will be updated. But this really depends on the data sent by the API. If you want to confirm, just console the parsed message. Alright, this is perfect, we can now get a real time price without having to refresh our page. But what if we need to change the currency? The task scheduler needs to be disrupted and the current task needs to be replaced with a new task that will call the API based on the currency that we choose. This is a going to be a problem, because recall that we are using PersistentScheduler, and we cannot simply change the tasks at runtime. So let's use a DatabaseScheduler where we can manage our tasks with a database table. However this does not come with Celery, we are going to have to install an extension package; &lt;code&gt;pip install django_celery_beat&lt;/code&gt;. And once it's done installing, include it under &lt;code&gt;INSTALLED_APPS&lt;/code&gt;. Since we want to use the table, don't forget to migrate it; &lt;code&gt;python manage.py migrate&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now let's add a simple dropdown to allow user to select a currency. Add the following JSX under App class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;label  for="currency"&amp;gt;Switch currency:&amp;lt;/label&amp;gt;
&amp;lt;select  name="currency"  id="currency"  onChange={handleCurrency}&amp;gt;
    &amp;lt;option  value="usd"&amp;gt;US Dollars&amp;lt;/option&amp;gt;
    &amp;lt;option  value="eur"&amp;gt;Euro&amp;lt;/option&amp;gt;
    &amp;lt;option  value="myr"&amp;gt;Malaysian Ringgit&amp;lt;/option&amp;gt;
    &amp;lt;option  value="btc"&amp;gt;Bitcoin&amp;lt;/option&amp;gt;
&amp;lt;/select&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;as well as the &lt;code&gt;handleCurrency&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const handleCurrency = () =&amp;gt; {
    const currency = document.getElementById("currency").value;
    socket.send(
        JSON.stringify({
            currency: currency,
        })
    );
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modify &lt;code&gt;consumers.py&lt;/code&gt; so it can receive the selected currency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import json

from asgiref.sync import sync_to_async
from channels.generic.websocket import AsyncWebsocketConsumer
from django_celery_beat.models import IntervalSchedule, PeriodicTask

from .tasks import get_coin_list

class CoinListConsumer(AsyncWebsocketConsumer):

    async def connect(self):
        await self.channel_layer.group_add('coin_list', self.channel_name)
        await self.accept()
        await self.send(json.dumps({'message': 'hey im server'}))

    @sync_to_async
    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        currency = text_data_json['currency']
        get_coin_list.delay(currency)

        schedule = IntervalSchedule.objects.create(every=30, period=IntervalSchedule.SECONDS)

        try:
            data = PeriodicTask.objects.get(name='Get coin list')
        except PeriodicTask.DoesNotExist:
            data = None

        if data is  None:
            PeriodicTask.objects.create(
                interval=schedule,
                name='Get coin list',
                task='coin.tasks.get_coin_list',
                args=json.dumps([currency]),
            )
        else:
            PeriodicTask.objects.filter(name='Get coin list').update(args=json.dumps([currency]))

    async def disconnect(self):
        await self.channel_layer.group_discard('coin_list', self.channel_name)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the receive method, we captured the currency sent from the client. And then we create an IntervalSchedule object. We're going to name our task as &lt;code&gt;'Get coin list'&lt;/code&gt;. So first we look the name up inside the PeriodicTask table. If it's not in the table, create one and set the currency as the arguments. If it already exists, simply update the argument. Since task scheduling is now handled here, we can remove the one we configured inside &lt;code&gt;celery.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also &lt;code&gt;get_coin_list&lt;/code&gt; method in &lt;code&gt;tasks.py&lt;/code&gt; should receive currency argument like so:&lt;br&gt;
For the sake of brevity, I omitted the rest of the code. View the complete code &lt;a href=""&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def get_coin_list(currency='usd'):
    data = requests.get(get_market_api(1, 100, currency)).json()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The celery beat needs to be restarted, but the command would be slightly different now that we want to use the database scheduler.&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;celery -A server beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
.&lt;/p&gt;

&lt;p&gt;Restart the worker as well and the command should be the same as before. Refresh the UI and select any currency and you should see the price changing accordingly. &lt;/p&gt;

&lt;h4&gt;
  
  
  References:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;An &lt;a href="https://sookocheff.com/post/networking/how-do-websockets-work/"&gt;article&lt;/a&gt; on WebSocket.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>django</category>
      <category>channels</category>
    </item>
    <item>
      <title>Working on a branch that depends on another branch</title>
      <dc:creator>aishahsofea</dc:creator>
      <pubDate>Fri, 05 Mar 2021 15:17:22 +0000</pubDate>
      <link>https://dev.to/aishahsofea/working-on-a-branch-that-depends-on-another-branch-2n62</link>
      <guid>https://dev.to/aishahsofea/working-on-a-branch-that-depends-on-another-branch-2n62</guid>
      <description>&lt;p&gt;Okay, let's imagine that you are assigned to work on 2 different features on 2 separate branches. Let's call these branches 'feature-A' and 'feature-B', and they both branch off a main branch called 'master'. &lt;/p&gt;

&lt;p&gt;So, what we'd do is that we go to master and checkout to feature-A from there:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout master&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git checkout -b feature-A&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;After working on feature-A and you are happy with your work, you'd push your changes to the remote branch and open a pull request. Now your work is under review. Cool. Now you're ready to move on to the next task, feature-B. Likewise, you checkout to master branch and again checkout feature-B from there:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout master&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git checkout -b feature-B&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now you've successfully created a new branch for feature-B and you are so thrilled to work on this exciting feature... until you realized that you can't actually work on it because you need the changes that are on feature-A! &lt;/p&gt;

&lt;p&gt;Okay, why don't just wait until feature-A is merged to master then just rebase master into feature-B? NO! You don't wait, what are you gonna say in tomorrow's stand-up?&lt;/p&gt;

&lt;p&gt;Luckily for you, git is very versatile and there are many ways to resolve this. But a solution that I like the most is the one by &lt;a href="https://softwareengineering.stackexchange.com/questions/351727/working-on-a-branch-with-a-dependence-on-another-branch-that-is-being-reviewed"&gt;AnoE on stackexchange&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main idea is that we need the changes that we made on feature-A in order to start working on feature-B. No problem, let's just get it! Make sure you are on feature-B and rebase feature-A:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout feature-B&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git rebase feature-A&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or you can delete feature-B and create a new one from feature-A instead (remember, you branched from master earlier)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git branch -d feature-B&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git checkout feature-A&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git checkout -b feature-B&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Cool, now that you have everything you need, you can work on feature-B like you normally would. And if there are any changes made on feature-A, you'd just rebase it as usual.&lt;/p&gt;

&lt;p&gt;Now, what would happen if feature-A is finally approved and merged to master? It means that feature-B does not have to be dependent on feature-A anymore because everything that was in feature-A is now on master. So feature-B should be dependent on master now. How do you go about doing this? Ok, pull all the latest changes into your local master branch:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout master&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git pull origin master&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, the moment of truth:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout feature-B&lt;/code&gt;&lt;br&gt;
&lt;code&gt;git rebase --onto master feature-A feature-B&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I don't know about you but when I first saw the last command, I couldn't make sense of it. What does &lt;code&gt;--onto&lt;/code&gt; mean? Why are we mentioning all the 3 branches in one command? That's a very loaded command. &lt;/p&gt;

&lt;p&gt;Generally, &lt;code&gt;git rebase --onto&lt;/code&gt; is a command that you should use if you want to change the parent branch. The formula is `git branch --onto new-parent-branch current-parent-branch child-branch. This is a &lt;a href="https://womanonrails.com/git-rebase-onto"&gt;good article&lt;/a&gt; explaining the topic. Also, technically, you don't have to specify the child branch if you are already on that branch, which in our case is feature-B. The command would be as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git checkout --onto master feature-A&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Awesome! Your feature-B is now again based off master!&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Linear Algebra Operations with PyTorch</title>
      <dc:creator>aishahsofea</dc:creator>
      <pubDate>Wed, 27 May 2020 11:15:55 +0000</pubDate>
      <link>https://dev.to/aishahsofea/linear-algebra-operations-with-pytorch-1bma</link>
      <guid>https://dev.to/aishahsofea/linear-algebra-operations-with-pytorch-1bma</guid>
      <description>&lt;p&gt;Linear algebra is a core mathematical concept in machine learning, especially deep learning, a sub-field of ML. There is a number of instances where linear algebra comes in handy when implementing neural network in deep learning. One of it is when dealing with unstructured data like images. An image consists of pixels which is commonly represented as a tensor or a matrix. In this blog post, I will briefly talk about basic linear algebra operations in PyTorch that are used in deep learning.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;code&gt;torch.dot()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This function allows us to perform dot product aka inner product between two vectors of the same size. The first element of &lt;code&gt;t1&lt;/code&gt; is multiplied with the first element of &lt;code&gt;t2&lt;/code&gt; and the second element of &lt;code&gt;t1&lt;/code&gt; is multiplied with the second element of &lt;code&gt;t2&lt;/code&gt; and so on and so forth. These products are then summed together. Note that a dot product between 2 vectors always returns a scalar value.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This operation is also commutative, in which &lt;code&gt;t1 . t2 = t2 . t1&lt;/code&gt;. If we pass in &lt;code&gt;t2&lt;/code&gt; as the first argument and &lt;code&gt;t1&lt;/code&gt; as the second argument, we will get the same answer. One thing to keep in mind is that the dot product only works if the vectors are of the same size. If not, it will spit out an error complaining about inconsistent number of elements.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  2. &lt;code&gt;torch.mm()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;torch.mm()&lt;/code&gt; is responsible for multiplication between 2 matrices. Similar to vector multiplication, matrix multiplication makes use of dot product and requires the matrices to have certain sizes. The number of columns of the first matrix must be equal to the number of rows of the second matrix. Each row of the first matrix will be transposed and multiplied against each column in the second matrix. This is basically a vector multiplication where each row in the first matrix is transposed to make sure it has the same dimension as each column in the second matrix.&lt;/p&gt;

&lt;p&gt;For example, the dot product is valid if the first matrix has a dimension of (3, 2) and the second matrix has a dimension of (2, 2). But not the other way around. A bunch of words might not help much, so let's look at a couple of examples.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Example 2 uses the same arguments as example 1, except that the order of the arguments is swapped. We can see that swapping the order results in a completely different outcome. So, unlike the dot product between 2 vectors, matrix multiplication is not commutative; &lt;code&gt;t1 x t2 != t2 x t1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example below shows that it is important to make sure the rows of the first matrix have the same number of entries as the columns of the second matrix.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  3. &lt;code&gt;torch.matmul()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This function performs multiplication, but it is not limited to certain shapes of tensors. &lt;code&gt;torch.matmul()&lt;/code&gt; allows us to do multiplication for different ranks of tensors. Based on PyTorch's official &lt;a href="https://pytorch.org/docs/stable/torch.html#torch.matmul"&gt;documentation&lt;/a&gt;, this function behaves according to the dimensionality of the input tensors. For instance, if both arguments are vectors of the same size, it will behave exactly like &lt;code&gt;torch.dot()&lt;/code&gt;. If both arguments are matrices, it will perform matrix multiplication similar to &lt;code&gt;torch.mm()&lt;/code&gt;. It also supports multiplication between a scalar and a matrix, by converting the scalar value into a rank-2 tensor so these 2 tensors will be compatible. In other words, it supports broadcasting. Check out this &lt;a href="https://deeplizard.com/learn/video/6_33ulFDuCg"&gt;blogpost&lt;/a&gt; for a detailed explanation on broadcasting.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In above example, &lt;code&gt;t1&lt;/code&gt; is a scalar value and &lt;code&gt;t2&lt;/code&gt; is a matrix. The way &lt;code&gt;matmul&lt;/code&gt; handles this is by pre-pending a &lt;code&gt;1&lt;/code&gt; to the dimension of &lt;code&gt;t1&lt;/code&gt; so the new dimension becomes &lt;code&gt;(1, 2)&lt;/code&gt;. It is now compatible with &lt;code&gt;t2&lt;/code&gt; that has a dimension of &lt;code&gt;(2, 3)&lt;/code&gt;. The pre-pended &lt;code&gt;1&lt;/code&gt; is removed after multiplication is performed.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;code&gt;torch.transpose()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Sometimes the tensor that we have is not the shape or dimension that we desire, and this happens a lot. So this is where transposing an array or a matrix comes in handy. One of the applications is when doing an operation within matrices itself, which I mentioned earlier in &lt;code&gt;torch.mm()&lt;/code&gt; section. In terms of a matrix, transposing can be thought of as flipping the elements over the diagonal axis. &lt;code&gt;torch.transpose()&lt;/code&gt; accepts 3 arguments; first argument being the tensor, second and third arguments being the dimensions that we want to swap.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The above example shows that we swap between dimension 0 and dimension 1, so the row of the output is the column of the input and vice versa.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;torch.transpose()&lt;/code&gt; allows us to swap between the same dimension, but it is the same as not swapping. So the output will be just the same as the input. Example below demonstrates this behavior:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  5. &lt;code&gt;torch.add()&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;So far, we haven't mentioned element-wise operation between tensors. There are a number of functions in PyTorch that allows us to do that and one of them is &lt;code&gt;torch.add()&lt;/code&gt;. In order to sum two matrices together, they must have the same size.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;t1&lt;/code&gt; and &lt;code&gt;t2&lt;/code&gt; are both (2, 2) matrices allowing values at the same position of the 2 matrices to be added together resulting in also a (2, 2) matrix.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Example above shows that the function supports broadcasting in which it modifies the dimension of &lt;code&gt;t1&lt;/code&gt; so it becomes compatible with the second argument, &lt;code&gt;t2&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;It is certainly important to have a good understanding and know when to implement a particular linear algebra operation if we want to delve into the world of deep learning. That being said, the list of functions above is far from exhaustive. Fret not, as we dive deeper, we are likely to discover more functions and the list will only grow from here on out!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>CartPole with Q-Learning</title>
      <dc:creator>aishahsofea</dc:creator>
      <pubDate>Wed, 13 May 2020 08:34:16 +0000</pubDate>
      <link>https://dev.to/aishahsofea/cartpole-with-q-learning-3jki</link>
      <guid>https://dev.to/aishahsofea/cartpole-with-q-learning-3jki</guid>
      <description>&lt;h3&gt;Motivation&lt;/h3&gt;

&lt;p&gt;I recently finished the &lt;a href="https://cs50.harvard.edu/ai/2020/"&gt;CS50 AI course&lt;/a&gt; by Harvard. If you are interested in learning modern AI concepts and looking to do hands-on projects, this course is for you. All you need is basic math and programming knowledge. Also, did I mention that it is completely free? Anyway, in week 4, we were introduced to different types of learning in Machine Learning; supervised learning, unsupervised learning, reinforcement learning along with commonplace algorithms like SVM, KNN-clustering and K-means.&lt;/p&gt;

&lt;p&gt;What caught my attention the most was the RL algorithm; Q-learning. Unlike most other algorithms, where we need to prepare the data before training, Q-learning(or just RL in general) collects the data while training, sort of. For the project assignment, we need to implement &lt;a href="https://en.wikipedia.org/wiki/Nim"&gt;Nim&lt;/a&gt;. Our agent is trained by playing against itself for 10,000 times prior to playing against a human. I would say the outcome was impressive, I mean, I lost 100% of the time. Anyhow, I wanted to reinforce(no pun intended) my understanding and implemented it for a different environment.&lt;/p&gt;

&lt;p&gt;Check out my &lt;a href="https://github.com/aishahsofea/cartpole"&gt;implementation&lt;/a&gt;!&lt;/p&gt;

&lt;h3&gt;CartPole Problem&lt;/h3&gt;

&lt;p&gt;Luckily for us, &lt;a href="https://gym.openai.com/"&gt;Open AI Gym&lt;/a&gt; provides a number of environments we can choose from. The most popular one is --&lt;em&gt;wait for it&lt;/em&gt;-- the CartPole, so I decided to go with that. Refer to &lt;a href="https://github.com/openai/gym/wiki/CartPole-v0"&gt;this wiki&lt;/a&gt; for the problem details.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It is considered solved when reward is greater than or equal to 195 over 100 consecutive trials.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5&gt;Challenges&lt;/h5&gt;

&lt;p&gt;Data collected during training is stored in Q-table. For problems with finite states like Nim, storing state-action pairs with their respective rewards is not an issue. However, for our cartpole environment, the states are continuous. To get a better idea, below are the minimum and maximum values for each variable.&lt;/p&gt;

&lt;p&gt;Maximum values:&lt;br&gt;
&lt;code&gt;[4.8000002e+00 3.4028235e+38 4.1887903e-01 3.4028235e+38]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Minimum values:&lt;br&gt;
&lt;code&gt;[-4.8000002e+00 -3.4028235e+38 -4.1887903e-01 -3.4028235e+38]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Imagine all the possible numbers between the max and min values, it is simply impossible to evaluate reward at each distinct state. For this reason, we have to descretize the values into buckets. Code to discretize state space is inspired by &lt;a href="https://github.com/sanjitjain2/q-learning-for-cartpole/blob/master/qlearning.py"&gt;sanjitjain2&lt;/a&gt; with some minor tweak.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CartPoleEnvironment():

    def __init__(self, buckets=(1, 1, 6, 12,)):
        self.env = gym.make('CartPole-v1')
        self.buckets = buckets

    def discretize(self, obs):
        """
        Convert continuous observation space into discrete values
        """
        high = self.env.observation_space.high
        low = self.env.observation_space.low
        upper_bounds = [high[0], high[1] / 1e38, high[2], high[3] / 1e38]
        lower_bounds = [low[0], low[1] / 1e38, low[2], low[3] / 1e38]

        ratios = [(obs[i] + abs(lower_bounds[i])) / (upper_bounds[i] - lower_bounds[i]) for i in range(len(obs))]
        new_obs = [int(round((self.buckets[i] - 1) * ratios[i])) for i in range(len(obs))]
        new_obs = [min(self.buckets[i] - 1, max(0, new_obs[i])) for i in range(len(obs))]

        return tuple(new_obs)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;Training&lt;/h5&gt;

&lt;p&gt;Our agent is trained for 5,000 episodes.&lt;/p&gt;

&lt;p&gt;For each episode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CartPole environment is initialized.&lt;/li&gt;
&lt;li&gt;Initial state is extracted from the environment.&lt;/li&gt;
&lt;li&gt;Exploration rate is decayed, since we want to explore less and exploit more over time.&lt;/li&gt;
&lt;li&gt;Agent can train for a maximum of 200 timesteps.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At each timestep:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using epsilon-greedy algorithm, select an action.&lt;/li&gt;
&lt;li&gt;Passing the selected action to the gym's &lt;code&gt;step()&lt;/code&gt; function, we can get the &lt;code&gt;new_state&lt;/code&gt;, &lt;code&gt;reward&lt;/code&gt; and &lt;code&gt;done&lt;/code&gt;. &lt;code&gt;done&lt;/code&gt; is true if the pole is no longer upright.&lt;/li&gt;
&lt;li&gt;Update our Q-table using Bellman equation.&lt;/li&gt;
&lt;li&gt;If the pole is no longer upright, break out of the loop and start a new episode.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Evaluation&lt;/h5&gt;

&lt;p&gt;For every 500 episodes, I average out the total rewards.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;500 : 30
1000: 54
1500: 82
2000: 110
2500: 127
3000: 145
3500: 158
4000: 183
4500: 175
5000: 196
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After 5000 episodes of training, the average rewards is starting to look good. This means that, on average (episode 4501-5000), the pole was upright up to 196 timesteps. In fact, for the last 300 episodes or so, the pole was upright for 200 timesteps. This shows that our agent indeed learns over time.&lt;/p&gt;

&lt;h5&gt;Observe trained agent&lt;/h5&gt;

&lt;p&gt;In &lt;code&gt;play()&lt;/code&gt; method, we initialize a new CartPole environment. By default, the maximum timesteps for each CartPole episode is 500. However, I want to observe the agent balancing the pole for at most 1000 steps. This can be easily achieved by setting &lt;code&gt;env._max_episode_steps = 1000&lt;/code&gt;. After the environment is set, we will render it for as long as &lt;code&gt;done = True&lt;/code&gt;. Note that we are now utilizing the populated Q-table and actions are selected based on greedy algorithm instead of epsilon-greedy.&lt;/p&gt;

&lt;p&gt;Outcome: Our agent does really well!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Agent finished with a reward of 1000.0&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;P/S&lt;/strong&gt;: Please check out &lt;a href="https://deeplizard.com/learn/video/HGeI30uATws"&gt;deeplizard&lt;/a&gt; for Q-learning implementation with Gym. Parts of my code are inspired by their implementation. They also have awesome tutorials on topics like Deep Learning, Neural Networks and how to put the knowledge together using tools like Keras and Pytorch.&lt;/p&gt;

</description>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
