diff --git a/AirtableDataset.py b/AirtableDataset.py new file mode 100644 index 0000000..e6cbb94 --- /dev/null +++ b/AirtableDataset.py @@ -0,0 +1,46 @@ +# %% +from airtable import Airtable +import pandas as pd + +base_id = 'app5x8nFdXg0Jj9JY' +table_name = '评分' +api_key = 'keyFvA03TJKPauBhh' + +AT = Airtable(base_id, table_name, api_key) +print(AT) + +# %% +view_name = 'Grid view' +records = AT.get_all(view=view_name) + +df = pd.DataFrame.from_records((r['fields'] for r in records)) +photos = df['房源照片'] +ranks = df['平均评分'] + +# %% +import requests + +def get_image(url, pic_name): + response = requests.get(url) + with open(pic_name, "wb") as fp: + for data in response.iter_content(128): + fp.write(data) + +# %% +s = len(photos) +for i in range(s): + pic_name = './data/%04d.png'%i + url = photos[i][0]['url'] + get_image(url, pic_name) + +# %% +with open('./data/label.txt', "w") as fopen: + for i in range(s): + pic_name = './data/%04d.png'%i + fopen.write(pic_name) + fopen.write('\t') + fopen.write(str(ranks[i])) + fopen.write('\n') + + +# %% diff --git a/ResizePic.py b/ResizePic.py new file mode 100644 index 0000000..a01653e --- /dev/null +++ b/ResizePic.py @@ -0,0 +1,25 @@ +# %% +import cv2 + +src = cv2.imread('F:/rangduju/cnn-classification/data/0000.png', cv2.IMREAD_UNCHANGED) +sw, sh, channels = src.shape +dw = int(sw/5) +dh = int(sh/5) +#inter = cv2.INTER_LINEAR +# 双线性插值。速度为最近邻和双三次的适中,效果也为二者适中。 +inter = cv2.INTER_AREA +# 区域插值,共分三种情况。图像放大时类似于双线性插值,图像缩小(x轴、y轴同时缩小)又分两种情况,均可避免波纹出现。 +#inter = cv2.INTER_LANCZOS4 +# 兰索斯插值。8*8,公式类似于双线性,计算量更大,效果更好,速度较慢。 +#iner = cv2.INTER_NEAREST +# 最近邻插值。因为没有插值,所以边缘会有严重的锯齿,放大后的图像有很严重的马赛克,缩小后的图像有很严重的失真。 +#inter = cv2.INTER_CUBIC +# 双三次插值。有效地避免出现锯齿现象,但速度最慢。放大时效果最好,但速度很慢。实际测试中并不慢,可能是优化的原因。 + +#dst = cv2.resize(src, (d_h, d_w), interpolation=inter) +dst = cv2.resize(src, (0,0), fx=0.2, fy=0.2, interpolation=inter) +cv2.imshow("dst",dst) +cv2.waitKey(0) +cv2.destroyAllWindows() +# area插值效果最好,5种算法中只有area可以看清车牌并且没有车牌边缘没有出现波纹,其他都多少出现扭曲。 +# %% diff --git a/cnn_classification.py b/cnn_classification.py new file mode 100644 index 0000000..1b6d7ec --- /dev/null +++ b/cnn_classification.py @@ -0,0 +1,110 @@ +#%% +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.optim as optim +from torchvision import datasets, transforms, models + +#%% +torch.manual_seed(53113) + +use_cuda = torch.cuda.is_available() +device = torch.device("cuda" if use_cuda else "cpu") +batch_size = test_batch_size =32 +kwargs = {'num_workers':0, 'pin_memory':True} if use_cuda else{} + +#%% +train_loader = torch.utils.data.DataLoader( + datasets.MNIST('./mnist_data', train=True, download=False, + transform=transforms.Compose( + [transforms.ToTensor(), + transforms.Normalize((0.1307,),(0.3081,))])), + batch_size=batch_size, shuffle=True,**kwargs +) + + +test_loader = torch.utils.data.DataLoader( + datasets.MNIST('./mnist_data', train=False, download=False, + transform=transforms.Compose( + [transforms.ToTensor(), + transforms.Normalize((0.1307,), (0.3081,))])), + batch_size=test_batch_size, + shuffle=True, **kwargs +) + +#%% +class Net(nn.Module): + def __init__(self): + super(Net, self).__init__() + self.conv1 = nn.Conv2d(1, 20, 5, 1) + self.conv2 = nn.Conv2d(20, 50, 5, 1) + self.fc1 = nn.Linear(4*4*50, 500) + self.fc2 = nn.Linear(500, 10) + + def forward(self, x): + x = F.relu(self.conv1(x)) + x = F.max_pool2d(x, 2, 2) + x = F.relu(self.conv2(x)) + x = F.max_pool2d(x, 2, 2) + x = x.view(-1, 4*4*50) + x = F.relu(self.fc1(x)) + x = self.fc2(x) + return F.log_softmax(x, dim=1) + # forward和__init__要对齐,NotImplementedError是没有检测到forward +# %% +lr = 1e-3 +momentum = 0.5 +model = Net().to(device) +optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum) + +#%% +def train(model, device, train_loader, optimizer, epoch, log_interval=100): + model.train() + for batch_idx,(data,target) in enumerate(train_loader): + data, target = data.to(device), target.to(device) + optimizer.zero_grad() + output = model(data) + loss = F.nll_loss(output, target) + + loss.backward() + optimizer.step() + if batch_idx % log_interval ==0: + print("Train Epoch:{} [{}/{} ({:0f}%)]\tLoss:{:.6f}".format( + epoch, + batch_idx * len(data), + len(train_loader.dataset), + 100.*batch_idx/len(train_loader), + loss.item() + )) + +#%% +def test(model, devivce, test_loader): + model.eval() + test_loss = 0 + correct = 0 + with torch.no_grad(): + for data, target in test_loader: + data, target = data.to(devivce), target.to(devivce) + output = model(data) + test_loss +=F.nll_loss(output, target, reduction='sum').item() + + pred = output.argmax(dim=1, keepdim=True) + correct +=pred.eq(target.view_as(pred)).sum().item() + + test_loss /= len(test_loader.dataset) + print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format( + test_loss, correct, len(test_loader.dataset), + 100. * correct / len(test_loader.dataset))) + +# %% +epochs = 2 +for epoch in range(1, epochs + 1): + train(model, device, train_loader, optimizer, epoch) + test(model, device, test_loader) + +save_model = True +if (save_model): + torch.save(model.state_dict(),"mnist_cnn.pt") + #词典格式,model.state_dict()只保存模型参数 + +# %% diff --git a/cnn_transfer.py b/cnn_transfer.py new file mode 100644 index 0000000..f667981 --- /dev/null +++ b/cnn_transfer.py @@ -0,0 +1,209 @@ +#%% +import numpy as np +import torch +import torchvision +import torch.nn as nn +from torchvision import datasets, transforms, models +import cv2 + +import matplotlib.pyplot as plt +import time +import os +import copy +print("Torchvision Version: ",torchvision.__version__) + +# %% +# Top level data directory. Here we assume the format of the directory conforms +# to the ImageFolder structure +data_dir = "./hymenoptera_data" +# Models to choose from [resnet, alexnet, vgg, squeezenet, densenet, inception] +model_name = "resnet" +# model_name = "alexnet" +# model_name = "vgg" +# Number of classes in the dataset +num_classes = 2 +# Batch size for training (change depending on how much memory you have) +batch_size = 32 +# Number of epochs to train for +num_epochs = 15 +# Flag for feature extracting. When False, we finetune the whole model, +# when True we only update the reshaped layer params +feature_extract = True + +input_size = 224 + +# %% +all_imgs = datasets.ImageFolder(os.path.join(data_dir, "train"), transforms.Compose([ + transforms.RandomResizedCrop(input_size), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + ])) +loader = torch.utils.data.DataLoader(all_imgs, + batch_size=batch_size, + shuffle=True, + num_workers=4) + +# %% +data_transforms = { + "train": transforms.Compose([ + transforms.RandomResizedCrop(input_size), + transforms.RandomHorizontalFlip(), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) + ]), + "val": transforms.Compose([ + transforms.Resize(input_size), + transforms.CenterCrop(input_size), + transforms.ToTensor(), + transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) + ]) +} + +image_datasets = {x: datasets.ImageFolder(os.path.join(data_dir, x), data_transforms[x]) for x in ["train", "val"]} + +dataloaders_dict = {x: torch.utils.data.DataLoader(image_datasets[x], + batch_size=batch_size, shuffle=True, num_workers=0) for x in ["train", "val"]} + +device = torch.device("cuda" if torch.cuda.is_available() else "cpu") + +# %% +img = next(iter(dataloaders_dict["val"]))[0] +print(img.shape) + +# %% +''' +unloader = transforms.ToPILImage() # reconvert into PIL image + +plt.ion() + +def imshow(tensor, title=None): + image = tensor.cpu().clone() # we clone the tensor to not do changes on it + image = image.squeeze(0) # remove the fake batch dimension + image = unloader(image) + plt.imshow(image) + if title is not None: + plt.title(title) + plt.pause(0.001) # pause a bit so that plots are updated + + +plt.figure() +imshow(img[11], title='Image') +''' + +# %% +def set_parameter_requires_grad(model, feature_extract): + if feature_extract: + for param in model.parameters(): + param.requires_grad = False + +def initialize_model(model_name, num_classes, feature_extract, use_pretrained=True): + if model_name == "resnet": + model_ft = models.resnet18(pretrained=use_pretrained) + set_parameter_requires_grad(model_ft, feature_extract) + num_ftrs = model_ft.fc.in_features + model_ft.fc = nn.Linear(num_ftrs, num_classes) + input_size = 224 + + elif model_name == "alexnet": + model_ft = models.alexnet(pretrained=use_pretrained) + set_parameter_requires_grad(model_ft, feature_extract) + s = len(model_ft.classifier) - 1 + num_ftrs = model_ft.classifier[s].in_features + model_ft.classifier[s] = nn.Linear(num_ftrs, num_classes) + input_size = 224 + + elif model_name == "vgg": + model_ft = models.vgg19_bn() + set_parameter_requires_grad(model_ft, feature_extract) + s = len(model_ft.classifier) - 1 + num_ftrs = model_ft.classifier[s].in_features + model_ft.classifier[s] = nn.Linear(num_ftrs, num_classes) + input_size = 224 + + else: + print("model not implemented") + return None, None + + return model_ft, input_size + +model_ft, input_size = initialize_model(model_name, + num_classes, feature_extract, use_pretrained=True) +print(model_ft) + +# %% +def train_model(model, dataloaders, loss_fn, optimizer, num_epochs=5): + best_model_wts = copy.deepcopy(model.state_dict()) + best_acc = 0. + val_acc_history = [] + for epoch in range(num_epochs): + for phase in ["train", "val"]: + running_loss = 0. + running_corrects = 0. + if phase == "train": + model.train() + else: + model.eval() + + for inputs, labels in dataloaders[phase]: + inputs, labels = inputs.to(device), labels.to(device) + + with torch.autograd.set_grad_enabled(phase=="train"): + outputs = model(inputs) # bsize * 2 + loss = loss_fn(outputs, labels) + + preds = outputs.argmax(dim=1) + if phase == "train": + optimizer.zero_grad() + loss.backward() + optimizer.step() + running_loss += loss.item() * inputs.size(0) + running_corrects += torch.sum(preds.view(-1) == labels.view(-1)).item() + + epoch_loss = running_loss / len(dataloaders[phase].dataset) + epoch_acc = running_corrects / len(dataloaders[phase].dataset) + + print("Phase {} loss: {}, acc: {}".format(phase, epoch_loss, epoch_acc)) + + if phase == "val" and epoch_acc > best_acc: + best_acc = epoch_acc + best_model_wts = copy.deepcopy(model.state_dict()) + if phase == "val": + val_acc_history.append(epoch_acc) + model.load_state_dict(best_model_wts) + return model, val_acc_history + +# %% +model_ft = model_ft.to(device) +optimizer = torch.optim.SGD(filter(lambda p: p.requires_grad, + model_ft.parameters()), lr=0.001, momentum=0.9) +loss_fn = nn.CrossEntropyLoss() +# %% +_, ohist = train_model(model_ft, dataloaders_dict, loss_fn, optimizer, num_epochs=num_epochs) + +# %% +model_scratch, _ = initialize_model(model_name, + num_classes, feature_extract=False, use_pretrained=False) +model_scratch = model_scratch.to(device) +optimizer = torch.optim.SGD(filter(lambda p: p.requires_grad, + model_scratch.parameters()), lr=0.001, momentum=0.9) +loss_fn = nn.CrossEntropyLoss() +_, scratch_hist = train_model(model_scratch, dataloaders_dict, loss_fn, optimizer, num_epochs=num_epochs) + +save_model = True +if (save_model): + torch.save(model_scratch.state_dict(),"cnn_transfer.pt") +# %% +# Plot the training curves of validation accuracy vs. number +# of training epochs for the transfer learning method and +# the model trained from scratch + +plt.figure() +plt.title("Validation Accuracy vs. Number of Training Epochs") +plt.xlabel("Training Epochs") +plt.ylabel("Validation Accuracy") +plt.plot(range(1,num_epochs+1),ohist,label="Pretrained") +plt.plot(range(1,num_epochs+1),scratch_hist,label="Scratch") +plt.ylim((0,1.)) +plt.xticks(np.arange(1, num_epochs+1, 1.0)) +plt.legend() +plt.show() \ No newline at end of file diff --git "a/\350\207\252\345\212\250\344\277\256\345\233\276.md" "b/\350\207\252\345\212\250\344\277\256\345\233\276.md" new file mode 100644 index 0000000..e380b59 --- /dev/null +++ "b/\350\207\252\345\212\250\344\277\256\345\233\276.md" @@ -0,0 +1,17 @@ +# 自动修图 + +## 功能 +* 图像去噪 +* 图像修复 +* 风格迁移 +* 去雨雪雾 + +## 项目介绍 +### 图像去噪 +利用各类传统滤波算法对图像去噪;也可利用深度学习的N2V等算法去噪。 +### 图像修复 +利用图块将缺省部分补全,并修复折痕大块噪点;也可利用变分自动编码机,GAN等深度学习算法生成新的完好图像。 +### 风格迁移 +利用传统的调整色调以及边缘的算法实现冷暖系,卡通系等风格的迁移;也可利用深度学习中迁移学习一类的算法,从大量图片中提取风格。 +### 去雨雪雾 +利用深度学习框架实现图像去雨,去雪,去雾等处理。