SE-AlexNet / convert_weights.py
JiayuMBao's picture
Upload folder using huggingface_hub
6e88f15 verified
Raw
History Blame Contribute Delete
4.55 kB
#!/usr/bin/env python3
"""
Convert trained .pth files to .safetensors format and place them in the
correct directory structure.
The source .pth files are read from the ZX2 external drive (read-only).
Output .safetensors files are written to the HuggingFace repo structure.
Usage:
python3 convert_weights.py
Requires:
pip install safetensors torch
"""
import os
import sys
import json
import torch
from safetensors.torch import save_file
# ── Path configuration ──
ZX2_BASE = '/Volumes/ZX2 1TB/se-alexnet/ClassifiedWithCondition'
REPO_ROOT = os.path.dirname(os.path.abspath(__file__))
# ── Mapping: (model_type, pretrain, squeeze) β†’ ZX2 source path ──
# Format: (config_dest_relpath, source_pth_path)
WEIGHT_MAPPINGS = [
# ── Raw AlexNet ──
('alexnet/facebased',
f'{ZX2_BASE}/RawAlexNet/FaceBased/AlexNet.pth'),
('alexnet/objectbased',
f'{ZX2_BASE}/RawAlexNet/ObjectBased/AlexNet.pth'),
# ── VGG16 ──
('vgg16/facebased',
f'{ZX2_BASE}/VGG16/FaceBased/vgg16Net.pth'),
('vgg16/objectbased',
f'{ZX2_BASE}/VGG16/ObjectBased/vgg16Net.pth'),
]
# ── SE Location 1 ──
for pretrain in ['FaceBased', 'ObjectBased']:
dest_pretrain = pretrain.lower()
for r in [2, 4, 8, 16, 32]:
dest = f'se-location1/{dest_pretrain}/squeeze-{r}'
src = f'{ZX2_BASE}/SELocate-1/{pretrain}/squeeze-{r}/AlexNet.pth'
WEIGHT_MAPPINGS.append((dest, src))
# ── SE Location 2 ──
for pretrain in ['FaceBased', 'ObjectBased']:
dest_pretrain = pretrain.lower()
for r in [2, 4, 8, 16, 32]:
dest = f'se-location2/{dest_pretrain}/squeeze-{r}'
src = f'{ZX2_BASE}/SELocate-2/{pretrain}/squeeze-{r}/AlexNet.pth'
WEIGHT_MAPPINGS.append((dest, src))
# ── SE Location 3 ──
for pretrain in ['FaceBased', 'ObjectBased']:
dest_pretrain = pretrain.lower()
for r in [2, 4, 8, 16, 32]:
dest = f'se-location3/{dest_pretrain}/squeeze-{r}'
src = f'{ZX2_BASE}/SELocate-3-best/{pretrain}/squeeze-{r}/AlexNet.pth'
WEIGHT_MAPPINGS.append((dest, src))
def convert_single(src_path, dest_dir, dest_name='model.safetensors'):
"""Convert a single .pth file to .safetensors."""
dest_path = os.path.join(REPO_ROOT, dest_dir, dest_name)
if os.path.exists(dest_path):
print(f' ⏭ {dest_dir}/model.safetensors already exists, skipping')
return
os.makedirs(os.path.join(REPO_ROOT, dest_dir), exist_ok=True)
print(f' Loading: {os.path.basename(src_path)} ...', end=' ', flush=True)
try:
state_dict = torch.load(src_path, map_location='cpu', weights_only=True)
except Exception as e:
print(f'ERROR: {e}')
return
# Unwrap checkpoint if needed
if 'model' in state_dict:
state_dict = state_dict['model']
# Check with config to verify compatibility
config_path = os.path.join(REPO_ROOT, dest_dir, 'config.json')
if os.path.exists(config_path):
with open(config_path) as f:
config = json.load(f)
# Optional: verify last layer dims match num_classes
last_linear_keys = [k for k in state_dict if 'weight' in k
and len(state_dict[k].shape) == 2]
if last_linear_keys:
last_w = state_dict[last_linear_keys[-1]]
expected = config.get('num_classes')
if expected and last_w.shape[0] != expected:
print(f'\n ⚠️ num_classes mismatch: state_dict={last_w.shape[0]}, '
f'config={expected}')
print(f'saving .safetensors ({len(state_dict)} keys) ...', end=' ', flush=True)
save_file(state_dict, dest_path)
size_mb = os.path.getsize(dest_path) / (1024 * 1024)
print(f'βœ“ ({size_mb:.0f} MB)')
def main():
print('=' * 60)
print('SE-AlexNet: .pth β†’ .safetensors Conversion')
print('=' * 60)
print(f'Source: {ZX2_BASE}')
print(f'Target: {REPO_ROOT}')
print(f'Total: {len(WEIGHT_MAPPINGS)} models to convert')
print()
success = 0
skipped = 0
failed = 0
for dest, src in WEIGHT_MAPPINGS:
if not os.path.exists(src):
print(f' βœ— MISSING: {src}')
failed += 1
continue
try:
convert_single(src, dest)
success += 1
except Exception as e:
print(f' βœ— FAILED: {e}')
failed += 1
print()
print(f'Done. {success} converted, {skipped} skipped, {failed} failed.')
if __name__ == '__main__':
main()