Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cookbook/client/server/transformer/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import os

os.environ['TWINKLE_TRUST_REMOTE_CODE'] = '0'
os.environ['TWINKLE_TRUST_REMOTE_CODE'] = '1'

from twinkle.server import launch_server

Expand Down
98 changes: 98 additions & 0 deletions cookbook/client/server/transformer/server_config_hybrid_lora.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Twinkle training server for Qwen/Qwen3.5-9B with Hybrid LoRA.

proxy_location: EveryNode

http_options:
host: 0.0.0.0
port: 8000

persistence:
mode: memory

applications:
- name: server
route_prefix: /api/v1
import_path: server
args:
server_config:
per_token_model_limit: 1
supported_models:
- Qwen/Qwen3.5-9B
deployments:
- name: TinkerCompatServer
max_ongoing_requests: 50
autoscaling_config:
min_replicas: 1
max_replicas: 1
target_ongoing_requests: 128
ray_actor_options:
num_cpus: 0.1
runtime_env:
env_vars:
TWINKLE_FAIL_FAST: "0"

- name: models-Qwen3.5-9B
route_prefix: /api/v1/model/Qwen/Qwen3.5-9B
import_path: model
args:
backend: transformers
train_mode: hybrid
model_id: "ms://Qwen/Qwen3.5-9B"
max_length: 10240
nproc_per_node: 4
device_group:
name: model
ranks: 4
device_type: cuda
device_mesh:
device_type: cuda
fsdp_size: 4
dp_size: 1
max_loras: 3
max_r: 64
target_modules: all-linear
hybrid:
allocation_path: /shared/config/qwen3_5_9b_hybrid_allocation.json
default_lr_lora: 2.5e-5
default_lr_fft: 1.0e-6
queue_config:
rps_limit: 100
tps_limit: 100000
adapter_config:
adapter_timeout: 1800
deployments:
- name: ModelManagement
autoscaling_config:
min_replicas: 1
max_replicas: 1
target_ongoing_requests: 16
ray_actor_options:
num_cpus: 0.1
runtime_env:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "1"
TWINKLE_FAIL_FAST: "0"

- name: processor
route_prefix: /api/v1/processor
import_path: processor
args:
ncpu_proc_per_node: 2
device_group:
name: model
ranks: 2
device_type: CPU
device_mesh:
device_type: CPU
dp_size: 2
deployments:
- name: ProcessorManagement
autoscaling_config:
min_replicas: 1
max_replicas: 1
target_ongoing_requests: 128
ray_actor_options:
num_cpus: 0.1
runtime_env:
env_vars:
TWINKLE_FAIL_FAST: "0"
83 changes: 83 additions & 0 deletions cookbook/client/twinkle/hybrid_self_cognition.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"""Train a Hybrid LoRA adapter on the self-cognition dataset.

Start the Hybrid Transformers server before running this script.
"""

import os

import dotenv
from peft import LoraConfig

from twinkle import get_logger, init_twinkle_client
from twinkle.dataloader import DataLoader
from twinkle.dataset import Dataset, DatasetMeta
from twinkle_client.model import MultiLoraTransformersModel

dotenv.load_dotenv('.env')

logger = get_logger()

BASE_MODEL = os.environ.get('TWINKLE_MODEL_ID', 'Qwen/Qwen3.5-9B')
BASE_URL = os.environ.get('TWINKLE_SERVER_URL', 'http://localhost:8000')
API_KEY = os.environ.get('TWINKLE_SERVER_TOKEN', 'EMPTY_TOKEN')
SAVE_DIR = os.environ.get('TWINKLE_SAVE_DIR', '/tmp/twinkle_hybrid_sft_output')
MAX_STEPS = int(os.environ.get('TWINKLE_MAX_STEPS', '10'))


def train():
init_twinkle_client(base_url=BASE_URL, api_key=API_KEY)

dataset = Dataset(dataset_meta=DatasetMeta('ms://swift/self-cognition', data_slice=range(500)))
dataset.set_template('Qwen3_5Template', model_id=f'ms://{BASE_MODEL}', max_length=512)
dataset.map('SelfCognitionProcessor', init_args={
'model_name': 'twinkle模型',
'model_author': 'ModelScope社区',
})
dataset.encode(batched=True)
dataloader = DataLoader(dataset=dataset, batch_size=4)

model = MultiLoraTransformersModel(model_id=f'ms://{BASE_MODEL}')
lora_config = LoraConfig(
r=64,
lora_alpha=128,
target_modules='all-linear',
)
model.add_adapter_to_model(
'default',
lora_config,
adapter_mode='hybrid',
save_dir=SAVE_DIR,
)
model.set_template('Qwen3_5Template')
model.set_processor('InputProcessor', padding_side='right')
model.set_loss('CrossEntropyLoss')
model.set_optimizer('Adam', lr_lora=2.5e-5, lr_fft=1e-6)

logger.info(model.get_train_configs().model_dump())
global_step = 0
for epoch in range(3):
logger.info(f'Starting epoch {epoch}')
for batch in dataloader:
model.forward_backward(inputs=batch)
model.clip_grad_and_step()
global_step += 1

if global_step % 2 == 0:
metric = model.calculate_metric(is_training=True)
logger.info(f'Current step: {global_step}, metric: {metric.result}')

if global_step >= MAX_STEPS:
break
if global_step >= MAX_STEPS:
break

checkpoint = model.save(
name=f'hybrid-checkpoint-step-{global_step}',
save_optimizer=True,
consumed_train_samples=dataloader.get_state()['consumed_train_samples'],
)
logger.info(f'Saved Hybrid checkpoint: {checkpoint}')


if __name__ == '__main__':
train()
Loading
Loading