首先是train部分
- import os
- import sys
- import json
-
- import torch
- import torch.nn as nn
- from torchvision import transforms, datasets
- import torch.optim as optim
- from tqdm import tqdm
-
- from model import vgg
-
-
- def main():
- device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
- print("using {} device.".format(device))
-
- data_transform = {
- "train": transforms.Compose([transforms.RandomResizedCrop(224),
- transforms.RandomHorizontalFlip(),
- transforms.ToTensor(),
- transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))]),
- "val": transforms.Compose([transforms.Resize((224, 224)),
- transforms.ToTensor(),
- transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}
-
- data_root = os.path.abspath(os.path.join(os.getcwd(), "../..")) # get data root path
- image_path = os.path.join(data_root, "data_set", "flower_data") # flower data set path
- assert os.path.exists(image_path), "{} path does not exist.".format(image_path)
- train_dataset = datasets.ImageFolder(root=os.path.join(image_path, "train"),
- transform=data_transform["train"])
- train_num = len(train_dataset)
-
- # {'daisy':0, 'dandelion':1, 'roses':2, 'sunflower':3, 'tulips':4}
- flower_list = train_dataset.class_to_idx
- cla_dict = dict((val, key) for key, val in flower_list.items())
- # write dict into json file
- json_str = json.dumps(cla_dict, indent=4)
- with open('class_indices.json', 'w') as json_file:
- json_file.write(json_str)
-
- batch_size = 32
- nw = min([os.cpu_count(), batch_size if batch_size > 1 else 0, 8]) # number of workers
- print('Using {} dataloader workers every process'.format(nw))
-
- train_loader = torch.utils.data.DataLoader(train_dataset,
- batch_size=batch_size, shuffle=True,
- num_workers=nw)
-
- validate_dataset = datasets.ImageFolder(root=os.path.join(image_path, "val"),
- transform=data_transform["val"])
- val_num = len(validate_dataset)
- validate_loader = torch.utils.data.DataLoader(validate_dataset,
- batch_size=batch_size, shuffle=False,
- num_workers=nw)
- print("using {} images for training, {} images for validation.".format(train_num,
- val_num))
-
- # test_data_iter = iter(validate_loader)
- # test_image, test_label = test_data_iter.next()
-
- model_name = "vgg16"
- net = vgg(model_name=model_name, num_classes=5, init_weights=True)
- net.to(device)
- loss_function = nn.CrossEntropyLoss()
- optimizer = optim.Adam(net.parameters(), lr=0.0001)
-
- epochs = 30
- best_acc = 0.0
- save_path = './{}Net.pth'.format(model_name)
- train_steps = len(train_loader)
- for epoch in range(epochs):
- # train
- net.train()
- running_loss = 0.0
- train_bar = tqdm(train_loader, file=sys.stdout)
- for step, data in enumerate(train_bar):
- images, labels = data
- optimizer.zero_grad()
- outputs = net(images.to(device))
- loss = loss_function(outputs, labels.to(device))
- loss.backward()
- optimizer.step()
-
- # print statistics
- running_loss += loss.item()
-
- train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,
- epochs,
- loss)
-
- # validate
- net.eval()
- acc = 0.0 # accumulate accurate number / epoch
- with torch.no_grad():
- val_bar = tqdm(validate_loader, file=sys.stdout)
- for val_data in val_bar:
- val_images, val_labels = val_data
- outputs = net(val_images.to(device))
- predict_y = torch.max(outputs, dim=1)[1]
- acc += torch.eq(predict_y, val_labels.to(device)).sum().item()
-
- val_accurate = acc / val_num
- print('[epoch %d] train_loss: %.3f val_accuracy: %.3f' %
- (epoch + 1, running_loss / train_steps, val_accurate))
-
- if val_accurate > best_acc:
- best_acc = val_accurate
- torch.save(net.state_dict(), save_path)
-
- print('Finished Training')
-
-
- if __name__ == '__main__':
- main()
def main():
device=torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print("using {} device".format(device))
data_transform={
"train":transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
]),
"val":transforms.Compose([
transforms.Resize(224),
transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
])
}
data_root=os.path.abspath(os.path.join(os.getcwd(),"../.."))
image_path=os.path.join(data_root,"data_set","flower_data")
assert os.path.exists(image_path), "{} path is not exist. ".format(image_path)
train_dataset=datasets.ImageFolder(root=os.path.join(image_path,"train"),
transform=data_transform["train"])
val_dataset=datasets.ImageFolder(root=os.path.join(image_path,"val"),
transform=data_transform["val"])
train_num=len(train_dataset)
这里和之前一样,需要注意绝对路径,使用dataset.Imagefolder很方便
flower_list=train_dataset.class_to_idx使用这个,很方便的给图片打数字标
cla_dict=dict((val,key) for key,val in flower_list.items())打包成字典
json_str=json.dumps(cla_dict,indent=4)
with open('class_indices.json','w') as json_file:
json_file.write(json_str)
写进json里面
接下来是load
model_name='vgg16'
net=vgg(model_name=model_name,num_classes=5,init_weights=True)
net.to(device)
loss_function=nn.CrossEntropyLoss()
optimizer=optim.Adam(net.parameters(),lr=0.00001)
epochs=30
best_acc=0.0
save_path='./{}Net.path'.format(model_name)
train_steps=len(train_loader)k
开始训练
for epoch in range(epochs):
net.train()
running_loss=0.0
train_bar=tqdm(train_loader,file=sys.stdout)
for step,data in enumerate(train_bar):
images,labels=data
optimizer.zero_grad()
outputs=net(images.to(device))
loss=loss_function(outputs,labels.to(device))
loss.backward()
optimizer.step()
running_loss+=loss.item()
train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,
epochs,
loss)
然后做测试
net.eval()
acc=0.0
with torch.no_grad():
val_bar=tqdm(val_loader,file=sys.stdout)
for val_data in val_bar:
val_images,val_labels=val_data
outputs=net(val_images.to(device))
predict_y=torch.max(outputs,dim=1)[1]
acc=acc+torch.eq(predict_y,val_labels.to(device).sum().item())
val_acc=acc/val_num
print('[epoch%d] train_loss: %.3f val_acc:%.3f'%(epoch+1,running_loss/train_steps,val_acc))b
保存模型:
if val_acc>best_acc:
best_acc=val_acc
torch.save(net.state_dict(),save_path)
然后是测试集:
- import os
- import json
-
- import torch
- from PIL import Image
- from torchvision import transforms
- import matplotlib.pyplot as plt
-
- from model import vgg
-
-
- def main():
- device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
-
- data_transform = transforms.Compose(
- [transforms.Resize((224, 224)),
- transforms.ToTensor(),
- transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
-
- # load image
- img_path = "../tulip.jpg"
- assert os.path.exists(img_path), "file: '{}' dose not exist.".format(img_path)
- img = Image.open(img_path)
- plt.imshow(img)
- # [N, C, H, W]
- img = data_transform(img)
- # expand batch dimension
- img = torch.unsqueeze(img, dim=0)
-
- # read class_indict
- json_path = './class_indices.json'
- assert os.path.exists(json_path), "file: '{}' dose not exist.".format(json_path)
-
- with open(json_path, "r") as f:
- class_indict = json.load(f)
-
- # create model
- model = vgg(model_name="vgg16", num_classes=5).to(device)
- # load model weights
- weights_path = "./vgg16Net.pth"
- assert os.path.exists(weights_path), "file: '{}' dose not exist.".format(weights_path)
- model.load_state_dict(torch.load(weights_path, map_location=device))
-
- model.eval()
- with torch.no_grad():
- # predict class
- output = torch.squeeze(model(img.to(device))).cpu()
- predict = torch.softmax(output, dim=0)
- predict_cla = torch.argmax(predict).numpy()
-
- print_res = "class: {} prob: {:.3}".format(class_indict[str(predict_cla)],
- predict[predict_cla].numpy())
- plt.title(print_res)
- for i in range(len(predict)):
- print("class: {:10} prob: {:.3}".format(class_indict[str(i)],
- predict[i].numpy()))
- plt.show()
-
-
- if __name__ == '__main__':
- main()
正常操作
def main():
device=torch.device("cuda: 0" if torch.cuda.is_available() else "cpu")
data_transform=transforms.Compose([
transforms.Resize((224,224)),
transforms.ToTensor(),
transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
])
img_path="../tulip.jpg"
assert os.path.exists(img_path) ,"{} is not exist".format(img_path)
img=Image.open(img_path)
plt.show(img)
img=data_transform
img=torch.unsqueeze(img,dim=0)
开始读json文件
json_path='./class_indices.json'
assert os.path.exists(json_path),"{} is not exist".format(json_path)
with open(json_path,"r") as f:
class_indict=json.load(f)
使用模型开始测试
model=vgg(model_name="vgg_16",num_class=5).to(device)
weights_path="./vgg16Net.pth"
assert os.path.exists(weights_path),"{} is not exist".format(weights_path)
model.load_state_dict(torch.load(weights_path,map_location=device))
model.eval()
with torch.no_grad():
output=model(img.to(device))
output=torch.squeeze(output).cpu()
predict=torch.softmax(output,dim=0)
predict_cla=torch.argmax(predict).numpy()
接下来是model
- import torch.nn as nn
- import torch
-
- # official pretrain weights
- model_urls = {
- 'vgg11': 'https://download.pytorch.org/models/vgg11-bbd30ac9.pth',
- 'vgg13': 'https://download.pytorch.org/models/vgg13-c768596a.pth',
- 'vgg16': 'https://download.pytorch.org/models/vgg16-397923af.pth',
- 'vgg19': 'https://download.pytorch.org/models/vgg19-dcbb9e9d.pth'
- }
-
-
- class VGG(nn.Module):
- def __init__(self, features, num_classes=1000, init_weights=False):
- super(VGG, self).__init__()
- self.features = features
- self.classifier = nn.Sequential(
- nn.Linear(512*7*7, 4096),
- nn.ReLU(True),
- nn.Dropout(p=0.5),
- nn.Linear(4096, 4096),
- nn.ReLU(True),
- nn.Dropout(p=0.5),
- nn.Linear(4096, num_classes)
- )
- if init_weights:
- self._initialize_weights()
-
- def forward(self, x):
- # N x 3 x 224 x 224
- x = self.features(x)
- # N x 512 x 7 x 7
- x = torch.flatten(x, start_dim=1)
- # N x 512*7*7
- x = self.classifier(x)
- return x
-
- def _initialize_weights(self):
- for m in self.modules():
- if isinstance(m, nn.Conv2d):
- # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
- nn.init.xavier_uniform_(m.weight)
- if m.bias is not None:
- nn.init.constant_(m.bias, 0)
- elif isinstance(m, nn.Linear):
- nn.init.xavier_uniform_(m.weight)
- # nn.init.normal_(m.weight, 0, 0.01)
- nn.init.constant_(m.bias, 0)
-
-
- def make_features(cfg: list):
- layers = []
- in_channels = 3
- for v in cfg:
- if v == "M":
- layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
- else:
- conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
- layers += [conv2d, nn.ReLU(True)]
- in_channels = v
- return nn.Sequential(*layers)
-
-
- cfgs = {
- 'vgg11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
- 'vgg13': [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
- 'vgg16': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M'],
- 'vgg19': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M', 512, 512, 512, 512, 'M'],
- }
-
-
- def vgg(model_name="vgg16", **kwargs):
- assert model_name in cfgs, "Warning: model number {} not in cfgs dict!".format(model_name)
- cfg = cfgs[model_name]
-
- model = VGG(make_features(cfg), **kwargs)
- return model
class VGG(nn.Module):
def __init__(self,features,num_classes=1000,init_weights=False):
super(VGG,self).__init__()
self.features=features
self.classifier=nn.Sequential(
nn.Linear(512 * 7 * 7, 4096),
nn.ReLU(True),
nn.Dropout(p=0.5),
nn.Linear(4096, 4096),
nn.ReLU(True),
nn.Dropout(p=0.5),
nn.Linear(4096, num_classes)
)
if init_weights:
self._initialize_weights()
调整维度,扁平化成线性的
def forward(self,x):
x=self.features(x)
x=torch.flatten(x,start_dim=1)
x=self.classifier(x)
return x
def make_features(cfg:list):
layers=[]
in_channels=3
for v in cfg:
if v=="M":
layers+=[nn.MaxPool2d(kernel_size=2,stride=2)]
else:
conv2d=nn.Conv2d(in_channels,v,kernel_size=3,padding=1)
layers+=[conv2d,nn.ReLU(True)]
in_channels=v
return nn.Sequential(*layers)