Instructions to use ZibinDong/ActionCodec2 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use ZibinDong/ActionCodec2 with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("ZibinDong/ActionCodec2", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 5,104 Bytes
7c09a0c 1bfc3f0 7c09a0c 1bfc3f0 7c09a0c 1bfc3f0 7c09a0c 1bfc3f0 7c09a0c 1bfc3f0 7c09a0c 1bfc3f0 7c09a0c 1bfc3f0 7c09a0c 1bfc3f0 7c09a0c 1bfc3f0 7c09a0c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 | """Shared NumPy quaternion operations using the xyzw convention."""
from __future__ import annotations
import numpy as np
from .native_backend import native_kernel
def _mapped(values, operation, width):
kernel = native_kernel("quaternion_map")
if kernel is None:
return None
array = np.asarray(values, dtype=np.float64)
return kernel(array.reshape(-1, array.shape[-1]), operation).reshape(*array.shape[:-1], width)
def normalize_quaternion(values: np.ndarray) -> np.ndarray:
"""Normalize quaternion rows and reject an undefined zero rotation."""
result = _mapped(values, "normalize", 4)
if result is not None:
return result
quaternions = np.asarray(values, dtype=np.float64)
norms = np.linalg.norm(quaternions, axis=-1, keepdims=True)
if np.any(norms < 1e-12):
raise ValueError("a pose contains a zero quaternion")
return quaternions / norms
def multiply_quaternions(left: np.ndarray, right: np.ndarray) -> np.ndarray:
"""Return the Hamilton product of broadcastable xyzw arrays."""
first = np.asarray(left, dtype=np.float64)
second = np.asarray(right, dtype=np.float64)
kernel = native_kernel("quaternion_multiply")
if kernel is not None:
first, second = np.broadcast_arrays(first, second)
return kernel(first.reshape(-1, 4), second.reshape(-1, 4)).reshape(first.shape)
first_vector, first_scalar = first[..., :3], first[..., 3:4]
second_vector, second_scalar = second[..., :3], second[..., 3:4]
return normalize_quaternion(
np.concatenate(
(
first_scalar * second_vector
+ second_scalar * first_vector
+ np.cross(first_vector, second_vector),
first_scalar * second_scalar
- np.sum(first_vector * second_vector, axis=-1, keepdims=True),
),
axis=-1,
)
)
def conjugate_quaternion(quaternion: np.ndarray) -> np.ndarray:
"""Return the conjugate of an xyzw quaternion array."""
native = _mapped(quaternion, "conjugate", 4)
if native is not None:
return native
result = np.asarray(quaternion, dtype=np.float64).copy()
result[..., :3] *= -1.0
return result
def rotvec_to_quaternion(rotvec: np.ndarray) -> np.ndarray:
"""Convert rotation vectors to xyzw quaternions."""
result = _mapped(rotvec, "from_rotvec", 4)
if result is not None:
return result
values = np.asarray(rotvec, dtype=np.float64)
angle = np.linalg.norm(values, axis=-1)
scale = np.full_like(angle, 0.5)
regular = angle >= 1e-12
scale[regular] = np.sin(0.5 * angle[regular]) / angle[regular]
return normalize_quaternion(
np.concatenate((values * scale[..., None], np.cos(0.5 * angle)[..., None]), axis=-1)
)
def quaternion_to_rotvec(quaternion: np.ndarray) -> np.ndarray:
"""Convert xyzw quaternions to shortest-path rotation vectors."""
result = _mapped(quaternion, "to_rotvec", 3)
if result is not None:
return result
values = normalize_quaternion(quaternion).copy()
values[values[..., 3] < 0.0] *= -1.0
vector_norm = np.linalg.norm(values[..., :3], axis=-1)
angle = 2.0 * np.arctan2(vector_norm, np.clip(values[..., 3], 0.0, 1.0))
scale = np.full_like(angle, 2.0)
regular = vector_norm >= 1e-12
scale[regular] = angle[regular] / vector_norm[regular]
return values[..., :3] * scale[..., None]
def euler_xyz_to_quaternion(euler: np.ndarray) -> np.ndarray:
"""Convert ``(N,3)`` XYZ Euler angles to xyzw quaternions."""
values = np.asarray(euler, dtype=np.float64)
if values.ndim != 2 or values.shape[1] != 3:
raise ValueError("XYZ Euler angles must have shape [N, 3]")
result = _mapped(values, "from_euler", 4)
if result is not None:
return result
half = 0.5 * values
sin_roll, sin_pitch, sin_yaw = np.sin(half).T
cos_roll, cos_pitch, cos_yaw = np.cos(half).T
result = np.empty((len(values), 4), dtype=np.float64)
result[:, 0] = sin_roll * cos_pitch * cos_yaw - cos_roll * sin_pitch * sin_yaw
result[:, 1] = cos_roll * sin_pitch * cos_yaw + sin_roll * cos_pitch * sin_yaw
result[:, 2] = cos_roll * cos_pitch * sin_yaw - sin_roll * sin_pitch * cos_yaw
result[:, 3] = cos_roll * cos_pitch * cos_yaw + sin_roll * sin_pitch * sin_yaw
return normalize_quaternion(result)
def quaternion_to_euler_xyz(quaternion: np.ndarray) -> np.ndarray:
"""Convert ``(N,4)`` xyzw quaternions to XYZ Euler angles."""
values = normalize_quaternion(quaternion)
if values.ndim != 2 or values.shape[1] != 4:
raise ValueError("xyzw quaternions must have shape [N, 4]")
result = _mapped(values, "to_euler", 3)
if result is not None:
return result
x, y, z, w = values.T
return np.stack(
(
np.arctan2(2.0 * (w * x + y * z), 1.0 - 2.0 * (x * x + y * y)),
np.arcsin(np.clip(2.0 * (w * y - z * x), -1.0, 1.0)),
np.arctan2(2.0 * (w * z + x * y), 1.0 - 2.0 * (y * y + z * z)),
),
axis=1,
)
|