Getting started with qUnits
[1]:
import qrobot
import time
Set up a basic qBrain
First, define a sensorial input:
[2]:
# Layer 0 - Unit 0
l0_unit0 = qrobot.qunits.SensorialUnit("l0_unit_0", Ts=0.1)
[3]:
l0_unit0
[3]:
SensorialUnit "l0_unit_0-214657"
name: l0_unit_0
id: l0_unit_0-214657
Ts: 0.1
Then, define a model and the desired bursts:
[4]:
qrobot.models.AngularModel(n=2, tau=10)
[4]:
[model: AngularModel, n: 2, tau: 10]
[5]:
qrobot.bursts.ZeroBurst()
[5]:
<qrobot.bursts.zeroburst.ZeroBurst at 0x7f4e7d348bb0>
[6]:
qrobot.bursts.OneBurst()
[6]:
<qrobot.bursts.oneburst.OneBurst at 0x7f4e7d361100>
You can use objects like those to create a basic qBrain:
[7]:
from qrobot.models import AngularModel
from qrobot.bursts import ZeroBurst, OneBurst
# Layer 1 - Unit 0
l1_unit0 = qrobot.qunits.QUnit(
name="l1_unit0",
model=AngularModel(n=1, tau=10),
burst=OneBurst(),
Ts=0.3,
in_qunits={0: l0_unit0.id}, # Will receive Input from l0_unit0, dim 0
)
# Layer 1 - Unit 1
l1_unit1 = qrobot.qunits.QUnit(
name="l1_unit1",
model=AngularModel(n=1, tau=25),
burst=ZeroBurst(),
Ts=0.2,
in_qunits={0: l0_unit0.id}, # Will receive input from l0_unit0, dim 1
)
[8]:
l1_unit0
[8]:
QUnit "l1_unit0-e96c53"
name: l1_unit0
id: l1_unit0-e96c53
model: [model: AngularModel, n: 1, tau: 10]
burst: <class 'qrobot.bursts.oneburst.OneBurst'>
query: [0.0]
Ts: 0.3
[9]:
l1_unit1
[9]:
QUnit "l1_unit1-77319d"
name: l1_unit1
id: l1_unit1-77319d
model: [model: AngularModel, n: 1, tau: 25]
burst: <class 'qrobot.bursts.zeroburst.ZeroBurst'>
query: [0.0]
Ts: 0.2
Inputs and queries
Check the default input for l0_unit0
:
[10]:
l0_unit0.scalar_reading
[10]:
0.0
The input units for each qUnit are:
[11]:
print(l1_unit0.in_qunits)
print(l1_unit1.in_qunits)
{0: 'l0_unit_0-214657'}
{0: 'l0_unit_0-214657'}
Modify l1_unit1
query:
[12]:
l1_unit1.query = 0.8
Real-time processing
[13]:
l0_unit0.start()
l1_unit0.start()
l1_unit1.start()
2023-06-12 20:16:08,194 — l0_unit_0-214657 — INFO — start:72 — Starting SensorialUnit
2023-06-12 20:16:08,206 — l1_unit0-e96c53 — INFO — start:72 — Starting QUnit
2023-06-12 20:16:08,218 — l1_unit1-77319d — INFO — start:72 — Starting QUnit
Visualize the time evolution of the system from the redis status for 30 seconds changing the input with a random input:
[14]:
import time
import json
from random import randint
from IPython.display import clear_output
statuses = []
refresh_time = 0.5 # Read statuses every 0.5 seconds
for i in range(int(30 * (1 / refresh_time))):
# Wait and then clean the output
time.sleep(refresh_time)
clear_output(wait=True)
# Change input every 2 second
if (i * refresh_time) % 2 == 0:
l0_unit0.scalar_reading = randint(0, 1000) / 1000
# Read statused and store it
status = qrobot.qunits.redis_utils.redis_status()
statuses.append(status)
# Print output
print(json.dumps(status, indent=1, sort_keys=True))
print(int(i * refresh_time), "/30 seconds")
# Plot graph
qbrain_graph = qrobot.graph(status)
qrobot.draw(qbrain_graph)
{
"l0_unit_0-214657 class": "SensorialUnit",
"l0_unit_0-214657 output": "0.077",
"l1_unit0-e96c53 class": "QUnit",
"l1_unit0-e96c53 in_qunits": "{\"0\": \"l0_unit_0-214657\"}",
"l1_unit0-e96c53 output": "1.0",
"l1_unit0-e96c53 query": "[0.0]",
"l1_unit0-e96c53 state": "1",
"l1_unit1-77319d class": "QUnit",
"l1_unit1-77319d in_qunits": "{\"0\": \"l0_unit_0-214657\"}",
"l1_unit1-77319d output": "1.0",
"l1_unit1-77319d query": "[0.8]",
"l1_unit1-77319d state": "0"
}
29 /30 seconds
Read manually the latest outputs of the qunits found on the redis database:
[15]:
l1_unit0.get_burst_output()
[15]:
1.0
[16]:
l1_unit1.get_burst_output()
[16]:
1.0
Stop the processing loops:
[17]:
l0_unit0.stop()
l1_unit0.stop()
l1_unit1.stop()
2023-06-12 20:16:40,653 — l0_unit_0-214657 — INFO — stop:83 — Stopping SensorialUnit
2023-06-12 20:16:40,655 — l0_unit_0-214657 — INFO — stop:85 — Cleaning redis
2023-06-12 20:16:40,661 — l1_unit0-e96c53 — INFO — stop:83 — Stopping QUnit
2023-06-12 20:16:40,663 — l1_unit0-e96c53 — INFO — stop:85 — Cleaning redis
2023-06-12 20:16:40,671 — l1_unit1-77319d — INFO — stop:83 — Stopping QUnit
2023-06-12 20:16:40,674 — l1_unit1-77319d — INFO — stop:85 — Cleaning redis
Flush the redis to clean all traces (should not be necessary if the qUnits processing loops stopped correctly):
[18]:
qrobot.qunits.redis_utils.redis_status()
[18]:
{}
[19]:
qrobot.qunits.redis_utils.flush_redis()
2023-06-12 20:16:40,703 — redis — INFO — flush_redis:81 — Flushing redis database
Visualize the results
We can visualize the time evolution of such time period:
[20]:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
status_df = pd.DataFrame(statuses)
units = [l0_unit0.id + " output", l1_unit0.id + " output", l1_unit1.id + " output"]
status_df = status_df[units]
status_df = status_df.astype(np.float64)
status_df.index = status_df.index * refresh_time
fig, ax = plt.subplots(1, 1, figsize=(15, 5))
# Plot time evolution
styles = ["g", "y", "b"]
status_df[units].plot(style=styles, ax=ax)
# Plot queries as dashed lines
ax.hlines(
y=l1_unit0.query, xmin=0, xmax=30, linewidth=1, color="y", linestyles="dashed"
)
ax.hlines(
y=l1_unit1.query, xmin=0, xmax=30, linewidth=1, color="b", linestyles="dashed"
)
plt.show()
Focusing on l1_unit0
:
[21]:
print(l1_unit0)
fig, ax = plt.subplots(1, 1, figsize=(15, 5))
# Plot time evolution
units = [l0_unit0.id + " output", l1_unit0.id + " output"]
styles = ["g", "b"]
status_df[units].plot(style=styles, ax=ax)
# Plot time windows
t_start = status_df[l1_unit0.id + " output"].dropna().index[0]
t_step = l1_unit0.model.tau * l1_unit0.Ts
t_windows = np.arange(t_start, 31, t_step)
plt.vlines(x=t_windows, ymin=0, ymax=1, colors="gray", ls="dotted", lw=1)
# Plot query as dashed line
ax.hlines(y=l1_unit0.query, xmin=t_start, xmax=30, linewidth=1, color="b", ls="dashed")
plt.show()
QUnit "l1_unit0-e96c53"
name: l1_unit0
id: l1_unit0-e96c53
model: [model: AngularModel, n: 1, tau: 10]
burst: <class 'qrobot.bursts.oneburst.OneBurst'>
query: [0.0]
Ts: 0.3
Focusing on l1_unit1
:
[22]:
print(l1_unit1)
fig, ax = plt.subplots(1, 1, figsize=(15, 5))
# Plot time evolution
units = [l0_unit0.id + " output", l1_unit1.id + " output"]
styles = ["g", "b"]
status_df[units].plot(style=styles, ax=ax)
# Plot time windows
t_start = status_df[l1_unit1.id + " output"].dropna().index[0]
t_step = l1_unit1.model.tau * l1_unit1.Ts
t_windows = np.arange(t_start, 31, t_step)
plt.vlines(x=t_windows, ymin=0, ymax=1, colors="gray", ls="dotted", lw=1)
# Plot query as dashed line
ax.hlines(y=l1_unit1.query, xmin=t_start, xmax=30, linewidth=1, color="b", ls="dashed")
plt.show()
QUnit "l1_unit1-77319d"
name: l1_unit1
id: l1_unit1-77319d
model: [model: AngularModel, n: 1, tau: 25]
burst: <class 'qrobot.bursts.zeroburst.ZeroBurst'>
query: [0.8]
Ts: 0.2
Detailed logs
Print the last 30 lines of the log:
[23]:
def print_log(filter_by: "list[str]" = None, n_lines: int = 30):
log_file = qrobot._logger.log_file()
i = 0
with open(log_file) as log:
for line in log.readlines()[-n_lines:]:
if filter_by is None or all(x in line for x in filter_by):
print(line, end="")
i += 1
if i >= n_lines:
break
print_log()
2023-06-12 20:16:40,114 — l0_unit_0-214657 — DEBUG — _unit_task:80 — Writing input on redis
2023-06-12 20:16:40,208 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 4/25
2023-06-12 20:16:40,212 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,220 — l0_unit_0-214657 — DEBUG — _unit_task:79 — scalar_reading=0.077
2023-06-12 20:16:40,220 — l0_unit_0-214657 — DEBUG — _unit_task:80 — Writing input on redis
2023-06-12 20:16:40,325 — l0_unit_0-214657 — DEBUG — _unit_task:79 — scalar_reading=0.077
2023-06-12 20:16:40,325 — l0_unit_0-214657 — DEBUG — _unit_task:80 — Writing input on redis
2023-06-12 20:16:40,329 — l1_unit0-e96c53 — DEBUG — _unit_task:198 — Temporal window event 4/10
2023-06-12 20:16:40,331 — l1_unit0-e96c53 — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,416 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 5/25
2023-06-12 20:16:40,421 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,429 — l0_unit_0-214657 — DEBUG — _unit_task:79 — scalar_reading=0.077
2023-06-12 20:16:40,429 — l0_unit_0-214657 — DEBUG — _unit_task:80 — Writing input on redis
2023-06-12 20:16:40,535 — l0_unit_0-214657 — DEBUG — _unit_task:79 — scalar_reading=0.077
2023-06-12 20:16:40,535 — l0_unit_0-214657 — DEBUG — _unit_task:80 — Writing input on redis
2023-06-12 20:16:40,624 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 6/25
2023-06-12 20:16:40,626 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,633 — l1_unit0-e96c53 — DEBUG — _unit_task:198 — Temporal window event 5/10
2023-06-12 20:16:40,635 — l1_unit0-e96c53 — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,640 — l0_unit_0-214657 — DEBUG — _unit_task:79 — scalar_reading=0.077
2023-06-12 20:16:40,640 — l0_unit_0-214657 — DEBUG — _unit_task:80 — Writing input on redis
2023-06-12 20:16:40,653 — l0_unit_0-214657 — INFO — stop:83 — Stopping SensorialUnit
2023-06-12 20:16:40,655 — l0_unit_0-214657 — INFO — stop:85 — Cleaning redis
2023-06-12 20:16:40,661 — l1_unit0-e96c53 — INFO — stop:83 — Stopping QUnit
2023-06-12 20:16:40,663 — l1_unit0-e96c53 — INFO — stop:85 — Cleaning redis
2023-06-12 20:16:40,671 — l1_unit1-77319d — INFO — stop:83 — Stopping QUnit
2023-06-12 20:16:40,674 — l1_unit1-77319d — INFO — stop:85 — Cleaning redis
2023-06-12 20:16:40,703 — redis — INFO — flush_redis:81 — Flushing redis database
2023-06-12 20:16:40,705 — redis — DEBUG — flush_redis:82 — Previous redis state: {}
2023-06-12 20:16:40,708 — redis — DEBUG — flush_redis:85 — Current redis state: {}
Print the last lines of the log only for l1_unit1
:
[24]:
print_log(["l1_unit1"], 200)
2023-06-12 20:16:35,810 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 8/25
2023-06-12 20:16:35,814 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.82]
2023-06-12 20:16:36,016 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 9/25
2023-06-12 20:16:36,017 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.82]
2023-06-12 20:16:36,218 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 10/25
2023-06-12 20:16:36,219 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.82]
2023-06-12 20:16:36,421 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 11/25
2023-06-12 20:16:36,426 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.82]
2023-06-12 20:16:36,630 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 12/25
2023-06-12 20:16:36,633 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.82]
2023-06-12 20:16:36,836 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 13/25
2023-06-12 20:16:36,841 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:37,044 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 14/25
2023-06-12 20:16:37,048 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:37,252 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 15/25
2023-06-12 20:16:37,258 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:37,462 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 16/25
2023-06-12 20:16:37,468 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:37,672 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 17/25
2023-06-12 20:16:37,677 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:37,881 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 18/25
2023-06-12 20:16:37,885 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:38,089 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 19/25
2023-06-12 20:16:38,092 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:38,295 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 20/25
2023-06-12 20:16:38,299 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:38,503 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 21/25
2023-06-12 20:16:38,510 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:38,713 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 22/25
2023-06-12 20:16:38,718 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:38,922 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 23/25
2023-06-12 20:16:38,928 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.608]
2023-06-12 20:16:39,132 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 24/25
2023-06-12 20:16:39,137 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:39,341 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 25/25
2023-06-12 20:16:39,346 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:39,349 — l1_unit1-77319d — DEBUG — _unit_task:212 — Querying for state [0.8]
2023-06-12 20:16:39,376 — l1_unit1-77319d — DEBUG — _unit_task:216 — Output state = 0
2023-06-12 20:16:39,376 — l1_unit1-77319d — DEBUG — _unit_task:218 — Opening a connection to redis...
2023-06-12 20:16:39,377 — l1_unit1-77319d — DEBUG — _unit_task:220 — Redis connected: Redis<ConnectionPool<Connection<host=localhost,port=6379,db=0>>>
2023-06-12 20:16:39,380 — l1_unit1-77319d — DEBUG — _unit_task:231 — Initializing a new temporal window
2023-06-12 20:16:39,582 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 1/25
2023-06-12 20:16:39,589 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:39,793 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 2/25
2023-06-12 20:16:39,797 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,002 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 3/25
2023-06-12 20:16:40,005 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,208 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 4/25
2023-06-12 20:16:40,212 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,416 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 5/25
2023-06-12 20:16:40,421 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,624 — l1_unit1-77319d — DEBUG — _unit_task:198 — Temporal window event 6/25
2023-06-12 20:16:40,626 — l1_unit1-77319d — DEBUG — _unit_task:203 — input_vector=[0.077]
2023-06-12 20:16:40,671 — l1_unit1-77319d — INFO — stop:83 — Stopping QUnit
2023-06-12 20:16:40,674 — l1_unit1-77319d — INFO — stop:85 — Cleaning redis
[25]:
print("Time window time:", l1_unit1.Ts * l1_unit1.model.tau, "seconds")
print_log(["l1_unit1", "Output state = "], 1000)
Time window time: 5.0 seconds
2023-06-12 20:16:18,500 — l1_unit1-77319d — DEBUG — _unit_task:216 — Output state = 0
2023-06-12 20:16:23,725 — l1_unit1-77319d — DEBUG — _unit_task:216 — Output state = 1
2023-06-12 20:16:28,941 — l1_unit1-77319d — DEBUG — _unit_task:216 — Output state = 1
2023-06-12 20:16:34,151 — l1_unit1-77319d — DEBUG — _unit_task:216 — Output state = 0
2023-06-12 20:16:39,376 — l1_unit1-77319d — DEBUG — _unit_task:216 — Output state = 0