Commit 1a93882b authored by jameskrw's avatar jameskrw
Browse files

Merge branch 'dev' of github.com:JamesKrW/vagen into dev

parents 6e36cb41 1e978b2d
Loading
Loading
Loading
Loading
+53 −2
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ cd ../

# vagen
git clone https://github.com/RAGEN-AI/VAGEN.git
cd vagen
cd VAGEN
bash scripts/install.sh
```

@@ -98,7 +98,7 @@ bash scripts/install.sh
# To reproduce our reults, first go to release branch of verl
cd ../verl
git checkout release
cd ../vagen
cd ../VAGEN

wandb login # login into wandb

@@ -115,6 +115,57 @@ bash vagen/examples/release_experiments/mask_loss.sh # aico - gae mask
```
Each run takes ~4 hours to reach 150 steps on 4 H100s. You can decrease testing frequency to speed up training. Training might be unstable due to loss spikes; we recommend restoring from the latest checkpoint when encountering such cases. We will resolve this issue in future work (see roadmap).

## Service and Environment Architecture
We introduce a new service-based architecture that addresses the challenges of managing multiple embodied environments for VLM agent training. This design enables efficient parallel processing across distributed systems, providing better scalability, standardization, and the ability to seamlessly integrate both rule-based rewards and reward models within the same framework

### Directory Structure
```
vagen/
├── env/
│   ├── base_service.py        # Abstract base class defining the service interface
│   ├── client.py              # Client for interacting with environment server
│   ├── server.py              # Server implementation for hosting environments
│   └── REGISTERED_ENV         # Registry mapping environment names to services
├── utils/
|   ├── serial.py              # Handle observation serilization from service to client
```

### Component Hierarchy
```
BaseService (ABC)
├── **Batch Methods**
    ├── create_environments_batch()
    ├── reset_batch()
    ├── step_batch()
    ├── compute_reward_batch()
    ├── get_system_prompts_batch()
    └── close_batch()

BatchEnvClient
├── **HTTP Communication**
├── **Batch Methods**
└── **Convenience Methods**

BatchEnvServer
├── **Service Management**
├── **Request Routing**
├── **Batch Method Implementation**
└── **Server Management**
```

### New Service Development
To develop a new environment service, you only need to:

- Create a service class that inherits from `BaseService`
- Register the service with `REGISTERED_ENV`

The FrozenLake service example demonstrates how to:
- Handle batch operations

The SVG service example demonstrates how to:
- Integrate Reward Models (like DINO) directly within the service
- Combine rule-based rewards with model-based rewards

## Algorithm Settings

| Setting           | GRPO | GAE | Bi-Level GAE | Turn-Wise GAE | Masked-GAE |
+10 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ pip install 'gym'
pip install 'gym-sokoban'
pip install 'matplotlib'
pip install 'gymnasium'
pip install 'flask'

echo "Installing flash-attn with no build isolation..."
pip install flash-attn --no-build-isolation
@@ -25,4 +26,13 @@ pip install flash-attn --no-build-isolation
echo "Installing vagen package..."
pip install -e .

echo "Installing Navigation dependencies"
pip install ai2thor==5.0.0
pip install numpy==1.25.1

echo "Installing FrozenLake dependencies"
pip install "bs4"
pip install "svgpathtools"
pip install "cairosvg"

echo "Installation complete!"
 No newline at end of file
+3 −25
Original line number Diff line number Diff line
## General Server
## For Development Usage
```
# Start a Server
python vagen/env/server.py
# Start a Server in debug mode
python vagen/env/server.py --debug
```
### Navigation
```
# Additional dependencies:
pip install ai2thor==5.0.0
pip install numpy==1.25.1

# For headless servers, additional setup is required:
# Install required packages
apt-get install -y pciutils
@@ -16,21 +12,3 @@ apt-get install -y xorg xserver-xorg-core xserver-xorg-video-dummy

# Start X server in a tmux window
python vagen/env/navigation/startx.py 1
 No newline at end of file

```

### FrozenLake
```
# Additional dependencies:
pip install gymnasium
pip install "gymnasium[toy-text]"
```

### SVG
```
# Additional dependencies:
pip install bs4
pip install svgpathtools
pip install cairosvg
pip install flask
```
 No newline at end of file
+84 −81
Original line number Diff line number Diff line
@@ -3,65 +3,7 @@ import base64
import numpy as np
from typing import Any, Dict, List, Tuple, Optional, Union

def serialize_pil_image(img) -> str:
    """
    Serialize a PIL Image to a base64 string.
    
    Args:
        img: PIL Image object
        
    Returns:
        Base64 encoded string of the image
    """
    buffer = io.BytesIO()
    img.save(buffer, format="PNG")
    img_str = base64.b64encode(buffer.getvalue()).decode('utf-8')
    return {"__pil_image__": img_str}

def deserialize_pil_image(serialized_data: Dict[str, str]):
    """
    Deserialize a base64 string back to a PIL Image.
    
    Args:
        serialized_data: Dictionary with "__pil_image__" key containing base64 string
        
    Returns:
        PIL Image object
    """
    from PIL import Image
    img_data = base64.b64decode(serialized_data["__pil_image__"])
    return Image.open(io.BytesIO(img_data))

def serialize_numpy_array(arr) -> Dict[str, Any]:
    """
    Serialize a numpy array to a serializable format.
    
    Args:
        arr: Numpy array
        
    Returns:
        Dictionary with serialized array data
    """
    return {
        "__numpy_array__": {
            "data": arr.tolist(),
            "dtype": str(arr.dtype),
            "shape": arr.shape
        }
    }

def deserialize_numpy_array(serialized_data: Dict[str, Any]):
    """
    Deserialize data back to a numpy array.
    
    Args:
        serialized_data: Dictionary with "__numpy_array__" key
        
    Returns:
        Numpy array
    """
    array_data = serialized_data["__numpy_array__"]
    return np.array(array_data["data"], dtype=np.dtype(array_data["dtype"])).reshape(array_data["shape"])
# -------------- serialize and deserialize observation --------------

def serialize_observation(observation: Dict[str, Any]) -> Dict[str, Any]:
    """
@@ -124,8 +66,7 @@ def deserialize_observation(serialized_obs: Dict[str, Any]) -> Dict[str, Any]:
    
    return deserialized_obs



# -------------- serialize and deserialize step (obs, reward, done, info) --------------
def serialize_step_result(result_tuple: Tuple[Dict, float, bool, Dict]) -> Tuple[Dict, float, bool, Dict]:
    """
    Serialize the step result tuple by handling NumPy types.
@@ -158,6 +99,88 @@ def serialize_step_result(result_tuple: Tuple[Dict, float, bool, Dict]) -> Tuple
    
    return (serialized_observation, serialized_reward, serialized_done, serialized_info)

def deserialize_step_result(serialized_result: Tuple[Dict, float, bool, Dict]) -> Tuple[Dict, float, bool, Dict]:
    """
    Deserialize the step result tuple.
    
    Args:
        serialized_result: The serialized tuple (observation, reward, done, info).
        
    Returns:
        The deserialized tuple.
    """
    serialized_observation, reward, done, serialized_info = serialized_result
    
    # Process the observation using the existing deserialize_observation function.
    observation = deserialize_observation(serialized_observation)
    
    # The info dictionary might contain objects that require special handling.
    info = deserialize_dict(serialized_info)
    
    return (observation, reward, done, info)

# -------------- utils for previous functions --------------

def serialize_pil_image(img) -> str:
    """
    Serialize a PIL Image to a base64 string.
    
    Args:
        img: PIL Image object
        
    Returns:
        Base64 encoded string of the image
    """
    buffer = io.BytesIO()
    img.save(buffer, format="PNG")
    img_str = base64.b64encode(buffer.getvalue()).decode('utf-8')
    return {"__pil_image__": img_str}

def deserialize_pil_image(serialized_data: Dict[str, str]):
    """
    Deserialize a base64 string back to a PIL Image.
    
    Args:
        serialized_data: Dictionary with "__pil_image__" key containing base64 string
        
    Returns:
        PIL Image object
    """
    from PIL import Image
    img_data = base64.b64decode(serialized_data["__pil_image__"])
    return Image.open(io.BytesIO(img_data))

def serialize_numpy_array(arr) -> Dict[str, Any]:
    """
    Serialize a numpy array to a serializable format.
    
    Args:
        arr: Numpy array
        
    Returns:
        Dictionary with serialized array data
    """
    return {
        "__numpy_array__": {
            "data": arr.tolist(),
            "dtype": str(arr.dtype),
            "shape": arr.shape
        }
    }

def deserialize_numpy_array(serialized_data: Dict[str, Any]):
    """
    Deserialize data back to a numpy array.
    
    Args:
        serialized_data: Dictionary with "__numpy_array__" key
        
    Returns:
        Numpy array
    """
    array_data = serialized_data["__numpy_array__"]
    return np.array(array_data["data"], dtype=np.dtype(array_data["dtype"])).reshape(array_data["shape"])

def serialize_dict(obj: Any) -> Any:
    """
    Recursively serialize objects that may contain NumPy types.
@@ -187,26 +210,6 @@ def serialize_dict(obj: Any) -> Any:
    else:
        return obj

def deserialize_step_result(serialized_result: Tuple[Dict, float, bool, Dict]) -> Tuple[Dict, float, bool, Dict]:
    """
    Deserialize the step result tuple.
    
    Args:
        serialized_result: The serialized tuple (observation, reward, done, info).
        
    Returns:
        The deserialized tuple.
    """
    serialized_observation, reward, done, serialized_info = serialized_result
    
    # Process the observation using the existing deserialize_observation function.
    observation = deserialize_observation(serialized_observation)
    
    # The info dictionary might contain objects that require special handling.
    info = deserialize_dict(serialized_info)
    
    return (observation, reward, done, info)

def deserialize_dict(obj: Any) -> Any:
    """
    Recursively deserialize any special objects in the dictionary.