Skip to content

[Re-opened] Added video logging to Tensorboard to enable visual monitoring on remote servers#110

Merged
tsampazk merged 2 commits into
aidudezzz:devfrom
TarekSaati:main
Apr 8, 2025
Merged

[Re-opened] Added video logging to Tensorboard to enable visual monitoring on remote servers#110
tsampazk merged 2 commits into
aidudezzz:devfrom
TarekSaati:main

Conversation

@TarekSaati

Copy link
Copy Markdown
Contributor

Hi everyone!
Since Deepworlds offers robotic training examples in virtualized environments that depend on intense trial and error, it is preferable to run simulations on a remote (Headless) GPU sever that one might not have the ability to open X sessions. However, even on desktop OS variants, visual monitoring is costly and training is often conducted with no-render option for acceleration. In addition, different performance metrics and parameters are monitored and updated periodically through Tensorboard logging. In light of this, it becomes more convenient for learners and developers to periodically monitor agent training visually by logging not only scalars, but videos captured by a front camera mounted on the robot. As one might see, this feature opens the door for not only visual monitoring, but also for visual navigation using advances CNN-based RL models as well!

Here is an example video for the resulted visualization tab added to Tensorboard.

visualization_preview

Changes (find_and_avoid_v2_robot_supervisor.py):

  • add camera device to FindAndAvoidV2RobotSupervisor __init__:
# Camera setup
# Add a camera device to capture frames
self.camera = self.getDevice("camera")  # Ensure you have a camera device named "camera" in your Webots world
  • implement render function in FindAndAvoidV2RobotSupervisor class:
    def render(self, mode='rgb_array'):
        '''
        We expect `render()` to return a uint8 array with values in [0, 255] or a float array
        with values in [0, 1], also the shape of image must be (channel, hight, width)
        '''
        if mode == 'rgb_array':
            # Capture the current frame from the camera
            frame_str = self.camera.getImage()      # Do NOT use getImageArray()
            H, W = self.camera.getHeight(), self.camera.getWidth()                
            frame = np.zeros(shape=(3, H, W), dtype=np.uint8)
            if frame_str is not None:                
                for x in range(W):
                    for y in range(H):
                        frame[0][y][x] = self.camera.imageGetRed(frame_str, W, x, y)
                        frame[1][y][x] = self.camera.imageGetGreen(frame_str, W, x, y)
                        frame[2][y][x] = self.camera.imageGetBlue(frame_str, W, x, y)
            return frame
        
        elif mode == 'human':
            # Display the frame in a window (optional, requires OpenCV or similar)
            frame = self.render(mode='rgb_array')
            if frame is not None:
                import cv2
                cv2.imshow("Webots Simulation", frame)
                cv2.waitKey(1)
        else:
            raise NotImplementedError(f"Render mode '{mode}' is not supported.")

Changes (training.py):

1- Import Video from logger:

from stable_baselines3.common.logger import HParam, Video

2- Add necessary variables to AdditionalInfoCallback class:
add in the constructor:

        self.frames = []  # List to store frames for GIF creation
        self.episode_cnt = 1
        self.record = False
        self.render_interval=render_interval

3- Implement the on_step() event handler to record frames periodically:

if self.env.done:
            if self.episode_cnt % self.render_interval == 0:
                self.env.camera.enable(self.env.timestep * 10) # basic time step = 32
                self.record = True
            else:
                self.env.camera.disable()
                self.record = False
            self.episode_cnt+=1
            self.frames = []
            print(f'Starting Episode {self.episode_cnt} ...')  

4- Add video creation and logging to tensorboard to on_rollout_end() event:

if self.record:
            # Save the frames to tensorboard
            frame = self.env.render(mode='rgb_array') # (c, h, w)
            self.frames.append(frame) 
            video = np.asarray([self.frames])
            self.logger.record("visualization",
                                Video(torch.from_numpy(video), fps=30),
                                exclude=("stdout", "log", "json", "csv"))

5- Add render parameters to run() function:

run(... ,
        log_interval=4,
        render_interval=100)

Notes:

  • This implementation was tested on Ubuntu 22.04 & NVIDIA GeForce RTX 4090 server.
  • Following steps are performed on a remote GPU server where you should have sudo & ssh access privileges.
  • Webots must be installed on your system beforehand (tested with Webots R2023a).

Steps to run:

  • First lets properly install deepbots. Connect and log into your remote machine then create conda environment:
conda create --name webots python=3.8.20
conda activate webots
  • Install Deepbots and xvfb wrapper to handle headless operation:
sudo apt install xvfb
pip install setuptools==65.5.0 pip==21 xvfbwrapper wheel==0.38.0
pip install deepbots==1.0.0
  • Run the following to install the video-enabled Deepworlds:
git clone https://github.com/TarekSaati/deepworlds.git
cd deepworlds
pip install -r requirements/requirements.txt
  • Now move to the example file with video enabled logging:
cd examples/find_and_avoid_with_video
  • Run Webots in headless mode using xvfb command:
xvfb-run --auto-servernum webots --mode=fast --no-rendering --stdout --stderr --minimize --batch ./worlds/find_avoid_v2_world.wbt
  • Now you can monitor your agent while training in a certain difficulty level:
    In a new prompt, run Tensorboard command with host 0.0.0.0 option to give clients access to Tensorboard:
tensorboard --logdir=./trained_agent/diff_0_0/ --host 0.0.0.0

Have fun monitoring your training agents!

@TarekSaati

Copy link
Copy Markdown
Contributor Author

My apologizes, the former PR was closed accidentally. I changed the example name as required. Have a nice day!

@tsampazk tsampazk linked an issue Apr 8, 2025 that may be closed by this pull request
@tsampazk tsampazk self-requested a review April 8, 2025 08:14
@tsampazk tsampazk added the enhancement New feature or request label Apr 8, 2025

@tsampazk tsampazk left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @TarekSaati ! As explained here, we can go ahead and merge this!

@tsampazk tsampazk merged commit 5d96955 into aidudezzz:dev Apr 8, 2025
@tsampazk

tsampazk commented Apr 8, 2025

Copy link
Copy Markdown
Member

@all-contributors please add @TarekSaati for code and examples !

@allcontributors

Copy link
Copy Markdown
Contributor

@tsampazk

I've put up a pull request to add @TarekSaati! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Video-enabled find_avoid example project

2 participants