# 🤖 AI Motion 模型開發與訓練全指南 (完整版)
本文件整合了從數據預處理、序列預測(Predictor)到隨機生成(VAE)的完整實作路徑。
---
## 📂 第一部分:動作序列預測模型 (Motion Predictor)
**目標**:輸入前 60 幀,預測下一幀(第 61 幀)。適用於動作補完或即時互動。
### 1. 模型架構
```python
import torch
import torch.nn as nn
class MotionPredictor(nn.Module):
def __init__(self, input_dim=120, model_dim=256, nhead=8, num_layers=3):
super().__init__()
# 位置編碼與投影
self.pos_encoder = nn.Parameter(torch.zeros(1, 60, model_dim))
self.input_projection = nn.Linear(input_dim, model_dim)
# Transformer Encoder
enc_layer = nn.TransformerEncoderLayer(d_model=model_dim, nhead=nhead, batch_first=True)
self.transformer_encoder = nn.TransformerEncoder(enc_layer, num_layers=num_layers)
# 輸出層:將特徵轉回原始維度
self.decoder = nn.Linear(model_dim, input_dim)
def forward(self, src):
# src: (Batch, 60, 120)
x = self.input_projection(src) + self.pos_encoder
x = self.transformer_encoder(x)
# 【預測邏輯】:取最後一幀的特徵來預測未來
out = self.decoder(x[:, -1, :])
return out # 返回 (Batch, 120)
```
### 2. 預測模型訓練代碼
```python
def train_predictor(model, dataloader, epochs=50):
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
criterion = nn.MSELoss() # 預測任務通常使用均方誤差
model.train()
for epoch in range(epochs):
for batch_x, batch_y in dataloader:
# batch_x: (Batch, 60, 120)
# batch_y: (Batch, 120) -> 真實的第 61 幀
optimizer.zero_grad()
output = model(batch_x)
loss = criterion(output, batch_y)
loss.backward()
optimizer.step()
print(f"Epoch {epoch+1}, Loss: {loss.item():.6f}")
```
---
## 🎨 第二部分:隨機動作生成模型 (Motion VAE)
**目標**:學習動作的「隱藏空間」,並從中隨機抽樣產生全新的動畫變體。
### 1. 模型架構 (含 Encoder 與 Decoder)
```python
class MotionVAE(nn.Module):
def __init__(self, input_dim=120, model_dim=256, latent_dim=64, seq_len=60):
super().__init__()
self.latent_dim = latent_dim
self.seq_len = seq_len
self.pos_encoder = nn.Parameter(torch.zeros(1, seq_len, model_dim))
# Encoder 支柱
self.enc_embed = nn.Linear(input_dim, model_dim)
self.encoder = nn.TransformerEncoder(
nn.TransformerEncoderLayer(d_model=model_dim, nhead=8, batch_first=True), num_layers=3)
self.fc_mu = nn.Linear(model_dim, latent_dim)
self.fc_logvar = nn.Linear(model_dim, latent_dim)
# Decoder 支柱
self.latent_to_model = nn.Linear(latent_dim, model_dim)
self.dec_transformer = nn.TransformerEncoder(
nn.TransformerEncoderLayer(d_model=model_dim, nhead=8, batch_first=True), num_layers=3)
self.final_out = nn.Linear(model_dim, input_dim)
def reparameterize(self, mu, logvar):
std = torch.exp(0.5 * logvar)
eps = torch.randn_like(std)
return mu + eps * std # 此處梯度會回傳至 mu 與 logvar
def forward(self, x):
# 壓縮過程
x_enc = self.encoder(self.enc_embed(x) + self.pos_encoder)
z_feat = x_enc[:, -1, :] # 取序列精華
mu, logvar = self.fc_mu(z_feat), self.fc_logvar(z_feat)
# 抽樣與還原
z = self.reparameterize(mu, logvar)
recon_x = self.decode(z)
return recon_x, mu, logvar
def decode(self, z):
"""隨機抽樣後調用此函數"""
z_emb = self.latent_to_model(z).unsqueeze(1).expand(-1, self.seq_len, -1)
z_emb = z_emb + self.pos_encoder
return self.final_out(self.dec_transformer(z_emb))
```
### 2. VAE 訓練代碼 (含雙重 Loss)
```python
def train_vae(model, dataloader, epochs=100):
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)
for epoch in range(epochs):
for data in dataloader: # data: (Batch, 60, 120)
optimizer.zero_grad()
recon_x, mu, logvar = model(data)
# 1. 重建誤差:確保動作正確
recon_loss = F.mse_loss(recon_x, data, reduction='sum')
# 2. KL 散度:確保隱藏空間整齊(梯度會校正 mu 和 logvar)
kl_loss = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())
loss = recon_loss + kl_loss
loss.backward()
optimizer.step()
print(f"Epoch {epoch+1}, Loss: {loss.item():.4f}")
```
---
## 🛠️ 第三部分:Houdini 與推理應用 (Inference)
### 1. 預測未來模式
* **用法**:將當前 60 幀餵入 Predictor,得到第 61 幀。
* **特性**:適合做物理連動或即時反應。
### 2. 隨機生成模式 (VAE Decode)
* **用法**:
```python
z = torch.randn(1, 64) # 從常態分佈抽樣(數值多在 -2 到 2)
new_motion = model.decode(z)
```
* **特性**:每次點擊按鈕,都會產生一段全新的類似動作。
* **Houdini 整合**:利用 **Slider** 控制 `latent_dim` 中的數值,你可以像調色盤一樣「滑動」出不同的動作風格。
---
## 💡 總結檢查清單 (Development Checklist)
1. **維度一致性**:`latent_dim` 是隱藏空間的維度,數值範圍在訓練後應趨向 。
2. **位置編碼**:在 Predictor 的 Encoder 以及 VAE 的 Decoder 中都是必須的。
3. **梯度傳導**:均值與對數方差透過 `reparameterize` 參與梯度更新,從而定義了有意義的隱藏空間。