Skip to content

Commit 8365ba5

Browse files
authored
Merge branch 'pytorch:main' into main
2 parents 2db1328 + 0cb38eb commit 8365ba5

File tree

4 files changed

+115
-26
lines changed

4 files changed

+115
-26
lines changed

fast_neural_style/neural_style/neural_style.py

+20-11
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def stylize(args):
131131
content_image = content_image.unsqueeze(0).to(device)
132132

133133
if args.model.endswith(".onnx"):
134-
output = stylize_onnx_caffe2(content_image, args)
134+
output = stylize_onnx(content_image, args)
135135
else:
136136
with torch.no_grad():
137137
style_model = TransformerNet()
@@ -142,31 +142,40 @@ def stylize(args):
142142
del state_dict[k]
143143
style_model.load_state_dict(state_dict)
144144
style_model.to(device)
145+
style_model.eval()
145146
if args.export_onnx:
146147
assert args.export_onnx.endswith(".onnx"), "Export model file should end with .onnx"
147-
output = torch.onnx._export(style_model, content_image, args.export_onnx).cpu()
148+
output = torch.onnx._export(
149+
style_model, content_image, args.export_onnx, opset_version=11,
150+
).cpu()
148151
else:
149152
output = style_model(content_image).cpu()
150153
utils.save_image(args.output_image, output[0])
151154

152155

153-
def stylize_onnx_caffe2(content_image, args):
156+
def stylize_onnx(content_image, args):
154157
"""
155-
Read ONNX model and run it using Caffe2
158+
Read ONNX model and run it using onnxruntime
156159
"""
157160

158161
assert not args.export_onnx
159162

160-
import onnx
161-
import onnx_caffe2.backend
163+
import onnxruntime
162164

163-
model = onnx.load(args.model)
165+
ort_session = onnxruntime.InferenceSession(args.model)
164166

165-
prepared_backend = onnx_caffe2.backend.prepare(model, device='CUDA' if args.cuda else 'CPU')
166-
inp = {model.graph.input[0].name: content_image.numpy()}
167-
c2_out = prepared_backend.run(inp)[0]
167+
def to_numpy(tensor):
168+
return (
169+
tensor.detach().cpu().numpy()
170+
if tensor.requires_grad
171+
else tensor.cpu().numpy()
172+
)
168173

169-
return torch.from_numpy(c2_out)
174+
ort_inputs = {ort_session.get_inputs()[0].name: to_numpy(content_image)}
175+
ort_outs = ort_session.run(None, ort_inputs)
176+
img_out_y = ort_outs[0]
177+
178+
return torch.from_numpy(img_out_y)
170179

171180

172181
def main():

imagenet/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This implements training of popular model architectures, such as ResNet, AlexNet
77
- Install PyTorch ([pytorch.org](http://pytorch.org))
88
- `pip install -r requirements.txt`
99
- Download the ImageNet dataset from http://www.image-net.org/
10-
- Then, and move validation images to labeled subfolders, using [the following shell script](https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh)
10+
- Then, move and extract the training and validation images to labeled subfolders, using [the following shell script](extract_ILSVRC.sh)
1111

1212
## Training
1313

imagenet/extract_ILSVRC.sh

+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#!/bin/bash
2+
#
3+
# script to extract ImageNet dataset
4+
# ILSVRC2012_img_train.tar (about 138 GB)
5+
# ILSVRC2012_img_val.tar (about 6.3 GB)
6+
# make sure ILSVRC2012_img_train.tar & ILSVRC2012_img_val.tar in your current directory
7+
#
8+
# Adapted from:
9+
# https://github.com/facebook/fb.resnet.torch/blob/master/INSTALL.md
10+
# https://gist.github.com/BIGBALLON/8a71d225eff18d88e469e6ea9b39cef4
11+
#
12+
# imagenet/train/
13+
# ├── n01440764
14+
# │ ├── n01440764_10026.JPEG
15+
# │ ├── n01440764_10027.JPEG
16+
# │ ├── ......
17+
# ├── ......
18+
# imagenet/val/
19+
# ├── n01440764
20+
# │ ├── ILSVRC2012_val_00000293.JPEG
21+
# │ ├── ILSVRC2012_val_00002138.JPEG
22+
# │ ├── ......
23+
# ├── ......
24+
#
25+
#
26+
# Make imagnet directory
27+
#
28+
mkdir imagenet
29+
#
30+
# Extract the training data:
31+
#
32+
# Create train directory; move .tar file; change directory
33+
mkdir imagenet/train && mv ILSVRC2012_img_train.tar imagenet/train/ && cd imagenet/train
34+
# Extract training set; remove compressed file
35+
tar -xvf ILSVRC2012_img_train.tar && rm -f ILSVRC2012_img_train.tar
36+
#
37+
# At this stage imagenet/train will contain 1000 compressed .tar files, one for each category
38+
#
39+
# For each .tar file:
40+
# 1. create directory with same name as .tar file
41+
# 2. extract and copy contents of .tar file into directory
42+
# 3. remove .tar file
43+
find . -name "*.tar" | while read NAME ; do mkdir -p "${NAME%.tar}"; tar -xvf "${NAME}" -C "${NAME%.tar}"; rm -f "${NAME}"; done
44+
#
45+
# This results in a training directory like so:
46+
#
47+
# imagenet/train/
48+
# ├── n01440764
49+
# │ ├── n01440764_10026.JPEG
50+
# │ ├── n01440764_10027.JPEG
51+
# │ ├── ......
52+
# ├── ......
53+
#
54+
# Change back to original directory
55+
cd ../..
56+
#
57+
# Extract the validation data and move images to subfolders:
58+
#
59+
# Create validation directory; move .tar file; change directory; extract validation .tar; remove compressed file
60+
mkdir imagenet/val && mv ILSVRC2012_img_val.tar imagenet/val/ && cd imagenet/val && tar -xvf ILSVRC2012_img_val.tar && rm -f ILSVRC2012_img_val.tar
61+
# get script from soumith and run; this script creates all class directories and moves images into corresponding directories
62+
wget -qO- https://raw.githubusercontent.com/soumith/imagenetloader.torch/master/valprep.sh | bash
63+
#
64+
# This results in a validation directory like so:
65+
#
66+
# imagenet/val/
67+
# ├── n01440764
68+
# │ ├── ILSVRC2012_val_00000293.JPEG
69+
# │ ├── ILSVRC2012_val_00002138.JPEG
70+
# │ ├── ......
71+
# ├── ......
72+
#
73+
#
74+
# Check total files after extract
75+
#
76+
# $ find train/ -name "*.JPEG" | wc -l
77+
# 1281167
78+
# $ find val/ -name "*.JPEG" | wc -l
79+
# 50000
80+
#

imagenet/main.py

+14-14
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import torch.backends.cudnn as cudnn
1313
import torch.distributed as dist
1414
import torch.optim
15+
from torch.optim.lr_scheduler import StepLR
1516
import torch.multiprocessing as mp
1617
import torch.utils.data
1718
import torch.utils.data.distributed
@@ -24,8 +25,8 @@
2425
and callable(models.__dict__[name]))
2526

2627
parser = argparse.ArgumentParser(description='PyTorch ImageNet Training')
27-
parser.add_argument('data', metavar='DIR',
28-
help='path to dataset')
28+
parser.add_argument('data', metavar='DIR', default='imagenet',
29+
help='path to dataset (default: imagenet)')
2930
parser.add_argument('-a', '--arch', metavar='ARCH', default='resnet18',
3031
choices=model_names,
3132
help='model architecture: ' +
@@ -148,7 +149,7 @@ def main_worker(gpu, ngpus_per_node, args):
148149
model.cuda(args.gpu)
149150
# When using a single GPU per process and per
150151
# DistributedDataParallel, we need to divide the batch size
151-
# ourselves based on the total number of GPUs we have
152+
# ourselves based on the total number of GPUs of the current node.
152153
args.batch_size = int(args.batch_size / ngpus_per_node)
153154
args.workers = int((args.workers + ngpus_per_node - 1) / ngpus_per_node)
154155
model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[args.gpu])
@@ -168,13 +169,16 @@ def main_worker(gpu, ngpus_per_node, args):
168169
else:
169170
model = torch.nn.DataParallel(model).cuda()
170171

171-
# define loss function (criterion) and optimizer
172+
# define loss function (criterion), optimizer, and learning rate scheduler
172173
criterion = nn.CrossEntropyLoss().cuda(args.gpu)
173174

174175
optimizer = torch.optim.SGD(model.parameters(), args.lr,
175176
momentum=args.momentum,
176177
weight_decay=args.weight_decay)
177-
178+
179+
"""Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""
180+
scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
181+
178182
# optionally resume from a checkpoint
179183
if args.resume:
180184
if os.path.isfile(args.resume):
@@ -192,6 +196,7 @@ def main_worker(gpu, ngpus_per_node, args):
192196
best_acc1 = best_acc1.to(args.gpu)
193197
model.load_state_dict(checkpoint['state_dict'])
194198
optimizer.load_state_dict(checkpoint['optimizer'])
199+
scheduler.load_state_dict(checkpoint['scheduler'])
195200
print("=> loaded checkpoint '{}' (epoch {})"
196201
.format(args.resume, checkpoint['epoch']))
197202
else:
@@ -240,14 +245,16 @@ def main_worker(gpu, ngpus_per_node, args):
240245
for epoch in range(args.start_epoch, args.epochs):
241246
if args.distributed:
242247
train_sampler.set_epoch(epoch)
243-
adjust_learning_rate(optimizer, epoch, args)
244248

245249
# train for one epoch
246250
train(train_loader, model, criterion, optimizer, epoch, args)
247251

248252
# evaluate on validation set
249253
acc1 = validate(val_loader, model, criterion, args)
254+
255+
scheduler.step()
250256

257+
251258
# remember best acc@1 and save checkpoint
252259
is_best = acc1 > best_acc1
253260
best_acc1 = max(acc1, best_acc1)
@@ -260,6 +267,7 @@ def main_worker(gpu, ngpus_per_node, args):
260267
'state_dict': model.state_dict(),
261268
'best_acc1': best_acc1,
262269
'optimizer' : optimizer.state_dict(),
270+
'scheduler' : scheduler.state_dict()
263271
}, is_best)
264272

265273

@@ -425,14 +433,6 @@ def _get_batch_fmtstr(self, num_batches):
425433
fmt = '{:' + str(num_digits) + 'd}'
426434
return '[' + fmt + '/' + fmt.format(num_batches) + ']'
427435

428-
429-
def adjust_learning_rate(optimizer, epoch, args):
430-
"""Sets the learning rate to the initial LR decayed by 10 every 30 epochs"""
431-
lr = args.lr * (0.1 ** (epoch // 30))
432-
for param_group in optimizer.param_groups:
433-
param_group['lr'] = lr
434-
435-
436436
def accuracy(output, target, topk=(1,)):
437437
"""Computes the accuracy over the k top predictions for the specified values of k"""
438438
with torch.no_grad():

0 commit comments

Comments
 (0)