pytorchでVGGをfinetuneし、cifar-100の分類を行います。
コードは以下の通り。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms, models
from torch.autograd import Variable
from PIL import Image

class Trainer():
def __init__(self, model, optimizer, train_loader):
self.model = model
self.optimizer = optimizer
self.train_loader = train_loader

def train_epoch(self):
self.model.train()
for batch_idx, (data, target) in enumerate(self.train_loader):
data, target = Variable(data.cuda()), Variable(target.cuda())
self.optimizer.zero_grad()
output = self.model(data)
criterion = nn.CrossEntropyLoss().cuda()
loss = criterion(output, target)
loss.backward()
optimizer.step()
print('[{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.data[0]))

def test(model, test_loader):
model.eval()
correct = 0
for batch_idx, (data, target) in enumerate(test_loader):
data, target = Variable(data.cuda(), requires_grad=False), Variable(target.cuda())
output = model(data)
pred = output.data.max(dim=1)[1]
correct += pred.eq(target.data).cpu().sum()

print('Accuracy: %d %%' % (
100 * correct / len(test_loader.dataset)))


if __name__ == '__main__':

# ネットワーク生成
model = models.vgg11(pretrained=True)

# ネットワークの変形
for p in model.features.parameters():
p.requires_grad = False
model.classifier = nn.Sequential(
nn.Linear(512 * 7 * 7, 4096),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(4096, 100)
)
model.cuda()

# cifar100 datasetの準備
transform = transforms.Compose([
transforms.Resize((224, 224), interpolation=Image.BICUBIC),
transforms.ToTensor()
])
train_set = datasets.CIFAR100(root='../data', train=True, transform=transform, download=True)
test_set = datasets.CIFAR100(root='../data', train=False, transform=transform, download=True)
batch_size = 50
train_loader = torch.utils.data.DataLoader(
train_set, batch_size=batch_size, shuffle=True, num_workers=1, pin_memory=True)
test_loader = torch.utils.data.DataLoader(
test_set, batch_size=batch_size, shuffle=True, num_workers=1, pin_memory=True)

# optimizer, trainer生成
optimizer = optim.SGD(model.classifier.parameters()), lr=0.01, momentum=0.5)
trainer = Trainer(model, optimizer, train_loader)

# 学習
epoch_num = 10
for epoch in range(epoch_num):
print('epoch :', epoch)
trainer.train_epoch()
test(model, test_loader)



わかりにくいと思われるところを解説します。
# ネットワークの変形
for p in model.features.parameters():
p.requires_grad = False

# optimizer, trainer生成
optimizer = optim.SGD(model.classifier.parameters(), lr=0.01, momentum=0.5)
conv層(model.features)のパラメータを固定し、全結合層(model.classifier)のみをfinetuneする設定です。
optimizerは、より汎用的に以下のように書くこともできます。
optimizer = optim.SGD(filter(lambda p: p.requires_grad, model.parameters()), lr=0.01, momentum=0.5)
全層のうち、requires_gradがTrueの層のみをfinetuneするという意味です。



model.classifier = nn.Sequential(
nn.Linear(512 * 7 * 7, 4096),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(4096, 4096),
nn.ReLU(True),
nn.Dropout(),
nn.Linear(4096, 100)
)

# cifar-100 datasetの準備
transform = transforms.Compose([
transforms.Resize((224, 224), interpolation=Image.BICUBIC),
transforms.ToTensor()
])
VGGの元々の定義(vgg.py)を参考に、全結合層を書き換えます。
出力層のユニット数を1000(Imagenetのクラス数)から100(cifar-100のクラス数)に変更するだけです。
また、cifar-100の画像は32×32なのですが、VGGは224×224の入力画像を想定しているので、
リサイズして入力するようにします。
(※古いversionのpytorchにはtransforms.Resize()が入ってません。ソースビルドしてください)

もしくは全結合層の入力サイズを入力画像サイズに応じて変更しても構いません。
例えば、Resize((128, 128), ...)として、入力画像サイズを128×128にし、
nn.Linear(512 * 4 * 4, 4096)として、全結合層の入力サイズを4×4にすることなどができます。

以上です。