mirror of
https://github.com/legop3/MultiRoombaRover.git
synced 2026-11-14 18:58:49 -05:00
slop
This commit is contained in:
@@ -8,6 +8,7 @@ from pathlib import Path
|
||||
|
||||
import av
|
||||
import numpy as np
|
||||
from observations import decision_frames, history_frames
|
||||
|
||||
from policy import SLOTS, VALUES, HEIGHT, WIDTH, SENSORS, command_family, is_stop, encode_command, sensor_vector
|
||||
|
||||
@@ -74,6 +75,7 @@ def prepare(directory, schema, stats, extend):
|
||||
candidate = copy.deepcopy(schema)
|
||||
history, targets, unsupported_times = [], [], []
|
||||
unsupported = {}
|
||||
dispatch_delays = []
|
||||
stats.update({'sensorFrames': len(sensors), 'dispatches': len(dispatches),
|
||||
'failedCommands': len(failed), 'sensorPresentFraction': np.mean([row[1][len(SENSORS):] for row in sensors], axis=0).tolist()})
|
||||
for data in dispatches:
|
||||
@@ -103,11 +105,17 @@ def prepare(directory, schema, stats, extend):
|
||||
target_time = request['ts']
|
||||
if not 0 <= stamp - target_time <= 1000:
|
||||
raise ValueError('Invalid request/dispatch timing')
|
||||
dispatch_delays.append(stamp - target_time)
|
||||
targets.append((target_time, *encoded))
|
||||
else:
|
||||
# Server safety overrides belong in history, never demonstration
|
||||
# targets. Exclude windows around them rather than teaching inaction.
|
||||
boundaries.append(stamp)
|
||||
stats['requestToDispatchMs'] = {'mean': sum(dispatch_delays) / max(1, len(dispatch_delays)),
|
||||
'max': max(dispatch_delays, default=0)}
|
||||
stats['acceptedCommandEvents'] = len(targets)
|
||||
stats['representedCommandEvents'] = 0
|
||||
stats['commandEventCounts'] = [0] * SLOTS
|
||||
stats['unsupportedCommands'] = list(unsupported.values())
|
||||
stats['unsupportedCommandEvents'] = len(unsupported_times) // 2
|
||||
if not targets and not unsupported_times:
|
||||
@@ -121,7 +129,7 @@ def windows(directory, schema, cancelled=lambda: False, stats=None, extend=True)
|
||||
stats = stats if stats is not None else {}
|
||||
metadata, sensors, history, targets, boundaries, unsupported_times = prepare(directory, schema, stats, extend)
|
||||
stats.update({'usableWindows': 0, 'commandWindows': 0, 'stopWindows': 0, 'noCommandWindows': 0,
|
||||
'staleSensorWindows': 0, 'boundaryWindows': 0,
|
||||
'staleSensorWindows': 0, 'boundaryWindows': 0, 'maxSensorAgeMs': 0, 'maxFrameAgeMs': 0,
|
||||
'unsupportedWindows': 0, 'ambiguousWindows': 0, 'videoFrames': 0, 'maxVideoGapMs': 0})
|
||||
sensor_times = [row[0] for row in sensors]
|
||||
target_times = [row[0] for row in targets]
|
||||
@@ -131,8 +139,9 @@ def windows(directory, schema, cancelled=lambda: False, stats=None, extend=True)
|
||||
command_times = np.full(SLOTS, -np.inf)
|
||||
cursor = 0
|
||||
recent = collections.deque(maxlen=32)
|
||||
last_sample, last_pts = -math.inf, -math.inf
|
||||
last_pts = -math.inf
|
||||
def frames():
|
||||
nonlocal last_pts
|
||||
files = metadata['video'].get('files', ['video.mkv'])
|
||||
for name in files:
|
||||
if Path(name).name != name:
|
||||
@@ -140,27 +149,24 @@ def windows(directory, schema, cancelled=lambda: False, stats=None, extend=True)
|
||||
with av.open(str(directory / name)) as container:
|
||||
stream = container.streams.video[0]
|
||||
stream.codec_context.thread_count = 1
|
||||
yield from container.decode(stream)
|
||||
for frame in container.decode(stream):
|
||||
if frame.pts is None:
|
||||
raise ValueError('Video frame has no timestamp')
|
||||
stamp = float(frame.pts * frame.time_base) * 1000
|
||||
stats['videoFrames'] += 1
|
||||
if math.isfinite(last_pts):
|
||||
stats['maxVideoGapMs'] = max(stats['maxVideoGapMs'], stamp - last_pts)
|
||||
last_pts = stamp
|
||||
if not metadata['startedAt'] - 2000 <= stamp <= metadata['endedAt'] + 2000:
|
||||
raise ValueError('Video PTS is not aligned to session Unix time')
|
||||
yield frame
|
||||
|
||||
for frame in frames():
|
||||
represented = set()
|
||||
for stamp, frame, captured_at in decision_frames(frames()):
|
||||
if cancelled():
|
||||
return
|
||||
if frame.pts is None:
|
||||
raise ValueError('Video frame has no timestamp')
|
||||
stamp = float(frame.pts * frame.time_base) * 1000
|
||||
if not math.isfinite(stamp) or stamp < last_pts:
|
||||
raise ValueError('Invalid/nonmonotonic video timestamps')
|
||||
stats['videoFrames'] += 1
|
||||
if math.isfinite(last_pts):
|
||||
stats['maxVideoGapMs'] = max(stats['maxVideoGapMs'], stamp - last_pts)
|
||||
last_pts = stamp
|
||||
if not metadata['startedAt'] - 2000 <= stamp <= metadata['endedAt'] + 2000:
|
||||
raise ValueError('Video PTS is not aligned to session Unix time')
|
||||
if stamp < metadata.get('trainingStartedAt', metadata['startedAt']):
|
||||
continue
|
||||
if stamp - last_sample < 99:
|
||||
continue
|
||||
last_sample = stamp
|
||||
while cursor < len(history) and history[cursor][0] < stamp:
|
||||
when, slot, values = history[cursor]
|
||||
# Do not let drive predictions simply copy earlier human/model drive commands.
|
||||
@@ -168,22 +174,19 @@ def windows(directory, schema, cancelled=lambda: False, stats=None, extend=True)
|
||||
command_values[slot] = values
|
||||
command_times[slot] = when
|
||||
cursor += 1
|
||||
sensor_index = bisect.bisect_right(sensor_times, stamp) - 1
|
||||
sensor_index = bisect.bisect_left(sensor_times, stamp) - 1
|
||||
if sensor_index < 0 or stamp - sensor_times[sensor_index] > 1000:
|
||||
stats['staleSensorWindows'] += 1
|
||||
recent.clear()
|
||||
continue
|
||||
stats['maxSensorAgeMs'] = max(stats['maxSensorAgeMs'], stamp - sensor_times[sensor_index])
|
||||
stats['maxFrameAgeMs'] = max(stats['maxFrameAgeMs'], stamp - captured_at)
|
||||
seen = np.isfinite(command_times).astype(np.float32)
|
||||
ages = np.minimum((stamp - command_times) / 10000, 1).astype(np.float32)
|
||||
state = np.concatenate((sensors[sensor_index][1], command_values.flatten(), ages, seen))
|
||||
pixels = frame.to_ndarray(width=WIDTH, height=HEIGHT, format='rgb24').transpose(2, 0, 1).copy()
|
||||
recent.append((stamp, pixels, state))
|
||||
chosen = []
|
||||
for offset in (900, 600, 300, 0):
|
||||
options = [row for row in recent if row[0] <= stamp - offset + 0.01]
|
||||
if not options or stamp - offset - options[-1][0] > 200:
|
||||
break
|
||||
chosen.append(options[-1])
|
||||
chosen = history_frames(recent, stamp)
|
||||
if len(chosen) != 4 or stamp + 100 > metadata['endedAt']:
|
||||
continue
|
||||
if bisect.bisect_right(unsupported_times, stamp + 100) > bisect.bisect_left(unsupported_times, chosen[0][0]):
|
||||
@@ -201,7 +204,7 @@ def windows(directory, schema, cancelled=lambda: False, stats=None, extend=True)
|
||||
for _, slot, vector in targets[start:end]:
|
||||
template = schema[slot]['template']
|
||||
family = command_family(template)
|
||||
if ((actions[slot] and (template['type'] in ('headlight', 'laser', 'horn', 'song', 'raw') or not np.array_equal(values[slot], vector)))
|
||||
if ((actions[slot] and (template['type'] in ('headlight', 'raw') or not np.array_equal(values[slot], vector)))
|
||||
or (not actions[slot] and family in families)):
|
||||
ambiguous = True
|
||||
break
|
||||
@@ -210,6 +213,10 @@ def windows(directory, schema, cancelled=lambda: False, stats=None, extend=True)
|
||||
if ambiguous:
|
||||
stats['ambiguousWindows'] += 1
|
||||
continue
|
||||
represented.update(range(start, end))
|
||||
stats['representedCommandEvents'] = len(represented)
|
||||
for slot in np.flatnonzero(actions):
|
||||
stats['commandEventCounts'][slot] += 1
|
||||
stats['usableWindows'] += 1
|
||||
stats['commandWindows' if actions.any() else 'noCommandWindows'] += 1
|
||||
stats['stopWindows'] += int(any(actions[slot] and is_stop(descriptor) for slot, descriptor in enumerate(schema)))
|
||||
|
||||
Reference in New Issue
Block a user