from PIL import Image from tqdm import tqdm import argparse import torch import torch.nn as nn import torchvision from torch.utils.data import DataLoader from torchvision import transforms from sklearn.metrics import mean_squared_error from sedna.common.config import Context, BaseConfig from sedna.datasources import TxtDataParse device = torch.device("cuda" if torch.cuda.is_available() else "cpu") def preprocess(train_data): x_data, y_data = train_data.x, train_data.y # preprocess label y_data = list(map(lambda y: [float(y)], y_data)) y_data = torch.tensor(y_data) # preprocess images transformed_images = [] for img_url in x_data: img = Image.open(img_url).convert('RGB') transformation = transforms.Compose([ transforms.ToTensor(), transforms.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)) ]) img = transformation(img).unsqueeze(0).to(device) transformed_images.append(img[0]) return transformed_images, y_data def set_args(**kwargs): parser = argparse.ArgumentParser(description="NeuralNetworkRegression Training") parser.add_argument("--learning-rate", type=float, default=0.001) parser.add_argument("--batch-size", type=int, default=20) parser.add_argument("--test-batch-size", type=int, default=1) parser.add_argument("--num-epoch", type=int, default=200) parser.add_argument("--hidden-size", type=int, default=32) parser.add_argument("--cuda", action="store_true", default=torch.cuda.is_available()) args = parser.parse_args() return args class NNRregressionNet(nn.Module): def __init__(self, backbone, hidden_size): super(NNRregressionNet, self).__init__() self.backbone = backbone self.fc1 = nn.Linear(1000, hidden_size) self.relu1 = nn.ReLU() self.fc2 = nn.Linear(hidden_size, 1) self.relu2 = nn.ReLU() def forward(self, x): out = self.backbone(x) out = self.fc1(out) out = self.relu1(out) out = self.fc2(out) return out class NNRegression(): def __init__(self, args): backbone = torchvision.models.resnet18(pretrained=True).to(device) self.args = args self.model = NNRregressionNet(backbone, args.hidden_size).to(device) self.criterion = nn.CrossEntropyLoss() self.optimizer = torch.optim.Adam(self.model.parameters(), lr=self.args.learning_rate) def train(self, train_data, valid_data=None): x_data, y_data = preprocess(train_data) train_data = list(zip(x_data, y_data)) train_data_loader = DataLoader(train_data, batch_size=self.args.batch_size, shuffle=True) for epoch in range(self.args.num_epoch): self.model.train() for i, (images, labels) in enumerate(tqdm(train_data_loader)): if self.args.cuda: images = images.cuda() labels = labels.cuda() # forward pass # 完整的模型为self.model # 假设forward只涉及第n+1层以后 new_model = nn.Sequential(*list(self.model.children())[n+1:]) # 将模型切片,不确定这样切片对不对,可以尝试其他 outputs = self.model(images) loss = self.criterion(outputs, labels) # backward and optimize self.optimizer.zero_grad() loss.backward() self.optimizer.step() def predict(self, data): self.model.eval() prediction = [] test_data_loader = DataLoader(data, batch_size=self.args.test_batch_size, shuffle=False) for image in tqdm(test_data_loader): if self.args.cuda: image = image.cuda() with torch.no_grad(): output = self.model(image) output = output.data.cpu().numpy()[0] prediction.append(output) return prediction def eval(self, data, metric=None): x_data, y_data = preprocess(data) y_data = y_data.data.cpu().numpy() prediction = self.predict(x_data) score = metric(y_data, prediction) return score def save(self, model_name): torch.save(self.model.state_dict(), model_name) return model_name def load(self, model_path): self.model.load_state_dict(torch.load(model_path)) def train(): train_dataset_url = "./data_txt/regression_train.txt" train_data = TxtDataParse(data_type="train") train_data.parse(train_dataset_url, use_raw=False) args = set_args() regressor = NNRegression(args) regressor.train(train_data) regressor.save("./models/nn_regression.pth") def eval(): test_dataset_url = "./data_txt/regression_test.txt" test_data = TxtDataParse(data_type="eval") test_data.parse(test_dataset_url, use_raw=False) args = set_args() regressor = NNRegression(args) regressor.load("./models/nn_regression.pth") eval_result = regressor.eval(test_data, metric=mean_squared_error) print("MSE:", eval_result) if __name__ == '__main__': eval()