Example #1
0
class Tester:
    """
    测试
    """
    def __init__(self, _hparams):
        self.test_loader = get_test_loader(_hparams)
        self.encoder = CNN().to(DEVICE)
        self.decoder = RNN(fea_dim=_hparams.fea_dim,
                           embed_dim=_hparams.embed_dim,
                           hid_dim=_hparams.hid_dim,
                           max_sen_len=_hparams.max_sen_len,
                           vocab_pkl=_hparams.vocab_pkl).to(DEVICE)
        self.test_cap = _hparams.test_cap

    def testing(self, save_path, test_path):
        """
        测试

        :param save_path: 模型的保存地址
        :param test_path: 保存测试过程生成句子的路径
        :return:
        """
        print('*' * 20, 'test', '*' * 20)
        self.load_models(save_path)
        self.set_eval()

        sen_json = []
        with torch.no_grad():
            for val_step, (img, img_id) in tqdm(enumerate(self.test_loader)):
                img = img.to(DEVICE)
                features = self.encoder.forward(img)
                sens, _ = self.decoder.sample(features)
                sen_json.append({'image_id': int(img_id), 'caption': sens[0]})

        with open(test_path, 'w') as f:
            json.dump(sen_json, f)

        result = coco_eval(self.test_cap, test_path)
        for metric, score in result:
            print(metric, score)

    def load_models(self, save_path):
        ckpt = torch.load(save_path,
                          map_location={'cuda:2': 'cuda:0'
                                        })  # 映射是因为解决保存模型的卡与加载模型的卡不一致的问题
        encoder_state_dict = ckpt['encoder_state_dict']
        self.encoder.load_state_dict(encoder_state_dict)
        decoder_state_dict = ckpt['decoder_state_dict']
        self.decoder.load_state_dict(decoder_state_dict)

    def set_eval(self):
        self.encoder.eval()
        self.decoder.eval()
Example #2
0
    total_step = 0  # 총 몇 번의 학습이 일어났나 저장하기 위한 객체
    list_loss = list()  # loss 저장용 리스트

    for epoch in trange(EPOCHS):  # EPOCHS 만큼 실행할 for 문
        for i, data in enumerate(
                data_loader):  # data_loader 에서 선언한 data 와 그 인덱스 i를 선언
            total_step += 1  # step을 1 늘림
            input, label = data[0], data[
                1]  # data_loader에서 읽은 data 객체의 인풋 데이터와 라벨 읽어옴
            # input shape = [32,1,28,28]  [batch size, channel, height, width]
            input = input.view(
                input.shape[0],
                -1) if model == 'MLP' else input  # 인풋 데이터를 1차원 행렬로 만듬
            # [batch size, channel*height*weight]

            classification_results = model.forward(input)  # [batch size, 10]
            #  MLP 클래스의 forward 부함수들 실행. 입력 데이터는 위에서 만든 input

            l = loss(classification_results,
                     label)  # loss 객체(Cross entropy) 에 forward 결과값과 라벨 입력
            list_loss.append(l.detach().item())  # loss_list 에 loss 저장.
            # l.detach(): 로스 계산을 하지 않겠다는 선언. 이미 l = loss 에서 로스를 계산했으니 필요 없음.
            # item(): tensor 형식으로 돌려줄 값을 float 형식으로 돌려줌

            optim.zero_grad(
            )  # make gradients zero. 각 웨이트가 부여받은 gradient를 0으로 만듬
            l.backward(
            )  # giving weight's gradient to each weights.  l 객체에서 구한 loss 값을 가중치들에 부여
            optim.step()  # Weights adjust themself using given gradient.
            # 각 객체가 부여받은 loss 값을 선언한 옵티마이저 설정에 맞게 수정하여 가중치에 반영
Example #3
0
    loss = nn.CrossEntropyLoss()
    optim = torch.optim.Adam(model.parameters(), lr=2e-4, betas=(0.5,0.99), eps=1e-8)       # parameters : wexight , optim : 그래디언트 전달 , lr: 계산되는 그래디언트의 값이 너무 크기 때문에 그래디언트에 붙이는 계수

    EPOCHS = 1                                                                 # 전체 데이터의 학습을 몇번 시킬 것인가?
    total_step = 0
    list_loss = list()
    for epoch in range(EPOCHS):
      for i, data in enumerate(data_loader):                                 # enumerate : 반복문에서 index를 입력할 때 사용
        total_step = total_step+1
        input, label = data[0], data[1]
        # input shape [32, 1, 28, 28] 첫번째 배치사이즈, channel, height, width
        input = input.view(input.shape[0], -1) if MODEL == 'MLP' else input   #
                                                    # batchsize, channel * height * width     왜 이렇게 하는거지 ? → 1차원으로 바꾸기 위해서
                                                    # view? reshape?  메모리주소?

        classification_results = model.forward(input) # [bstch size, 10] #nn.module을 상속한 클래스는 forward를 생략해도된다.

        l = loss(classification_results, label)
        list_loss.append(l.detach().item())         # detach 그래디언트를 없애는 item : torch tensor를 파이썬의 float이나 int로 바꿔줌

        optim.zero_grad()                           # 그래디언트를 초기화(
        l.backward()                                # l을 출력하기 까지의 해당하는 각각의 그래디언트를 돌려줌
        optim.step()                                # 이건 뭐냐 그래디언트를 각레이어로 전달해주는 거 맞나,,
        print(i)

    torch.save(model, '{}.pt'.format(MODEL))
    # 'MLP.pt', 'CNN.pt'
    plt.figure() #figure : 도화지
    plt.plot(range(len(list_loss)), list_loss, linestyle='--')
    plt.show()
Example #4
0
class TextClassifier:
    def __init__(self,
                 paths,
                 batch_size=6,
                 iterations=50,
                 initial_lr=0.003,
                 hidden_size=256,
                 dropout=0.2,
                 kernel_sz=3):

        self.use_cuda = torch.cuda.is_available()
        self.device = torch.device('cuda:0' if self.use_cuda else 'cpu')

        self.data = DataReader(paths)
        self.data.set_training_data(batch_size,
                                    ('cuda:0' if self.use_cuda else 'cpu'))
        self.train_batch_loader = BatchGenerator(self.data.train_data,
                                                 'Sentence', 'Label')
        self.val_batch_loader = BatchGenerator(self.data.val_data, 'Sentence',
                                               'Label')
        self.test_batch_loader = BatchGenerator(self.data.test_data,
                                                'Sentence', 'Label')

        # Store hyperparameters
        self.batch_size = batch_size
        self.iterations = iterations
        self.initial_lr = initial_lr
        self.kernel_sz = kernel_sz

        # Create Model
        emb_size, emb_dim = self.data.TEXT.vocab.vectors.size()
        self.cnn_model = CNN(emb_size=emb_size,
                             emb_dimension=emb_dim,
                             n_out=len(self.data.LABEL.vocab),
                             dropout=dropout,
                             kernel_sz=kernel_sz,
                             stride=1,
                             padding=0,
                             out_filters=hidden_size,
                             pretrained_emb=self.data.TEXT.vocab.vectors)

        if self.use_cuda:
            self.cnn_model.cuda()

    def train(self):

        train_loss_hist = []
        val_loss_hist = []
        train_acc_hist = []
        val_acc_hist = []
        test_acc_hist = []

        loss = 0.0

        best_model = 0.0

        for itr in range(self.iterations):
            print("\nIteration: " + str(itr + 1))
            optimizer = optim.SGD(self.cnn_model.parameters(),
                                  lr=self.initial_lr)
            self.cnn_model.train()
            total_loss = 0.0
            total_acc = 0.0
            steps = 0

            data_iter = iter(self.train_batch_loader)

            # For some reason using for loop on iterator (next) is missing the target variable (y)
            # Have to loop over the length and retrieve the batch_data inside the loop
            for i in range(len(self.train_batch_loader)):

                ((x_batch, x_len_batch), y_batch) = next(data_iter)

                #                 if torch.min(x_len_batch) > self.kernel_sz:
                optimizer.zero_grad()

                loss, logits = self.cnn_model.forward(x_batch, y_batch)

                acc = torch.sum(torch.argmax(logits, dim=1) == y_batch)

                total_loss += loss.item()
                total_acc += acc.item()
                steps += 1

                loss.backward()

                optimizer.step()

            train_loss_hist.append(total_loss / steps)
            train_acc_hist.append(total_acc / len(self.data.trainds))

            val_loss, val_acc = self.eval_model(self.val_batch_loader,
                                                len(self.data.valds))

            val_loss_hist.append(val_loss)
            val_acc_hist.append(val_acc)

            if best_model < val_acc:
                best_model = val_acc
                test_loss, test_acc = self.eval_model(self.test_batch_loader,
                                                      len(self.data.testds))

            print("Train: {Loss: " + str(total_loss / steps) + ", Acc: " +
                  str(total_acc / len(self.data.trainds)) + " }")
            print("Val: {Loss: " + str(val_loss) + ", Acc: " + str(val_acc) +
                  " }")

#         test_loss, test_acc = self.eval_model(self.test_batch_loader, len(self.data.testds) )

        test_acc_hist.append(test_acc)

        return train_loss_hist, train_acc_hist, val_loss_hist, val_acc_hist, test_acc

    def eval_model(self, batch_loader, N):
        self.cnn_model.eval()

        total_loss = 0.0
        total_acc = 0.0
        steps = 0

        batch_iter = iter(batch_loader)

        with torch.no_grad():
            for i in range(len(batch_loader)):

                ((x_batch, x_len_batch), y_batch) = next(batch_iter)

                loss, logits = self.cnn_model(x_batch, y_batch)

                acc = torch.sum(torch.argmax(logits, dim=1) == y_batch)

                total_loss += loss.item()
                total_acc += acc.item()
                steps += 1

        return (total_loss / steps), (total_acc / N)
Example #5
0
class Trainer:
    """
    训练
    """
    def __init__(self, _hparams):
        utils.set_seed(_hparams.fixed_seed)

        self.train_loader = get_train_loader(_hparams)
        self.val_loader = get_val_loader(_hparams)
        self.encoder = CNN().to(DEVICE)
        self.decoder = RNN(fea_dim=_hparams.fea_dim,
                           embed_dim=_hparams.embed_dim,
                           hid_dim=_hparams.hid_dim,
                           max_sen_len=_hparams.max_sen_len,
                           vocab_pkl=_hparams.vocab_pkl).to(DEVICE)
        self.loss_fn = nn.CrossEntropyLoss()
        self.optimizer = torch.optim.Adam(self.get_params(), lr=_hparams.lr)
        self.writer = SummaryWriter()

        self.max_sen_len = _hparams.max_sen_len
        self.val_cap = _hparams.val_cap
        self.ft_encoder_lr = _hparams.ft_encoder_lr
        self.ft_decoder_lr = _hparams.ft_decoder_lr
        self.best_CIDEr = 0

    def fine_tune_encoder(self, fine_tune_epochs, val_interval, save_path,
                          val_path):
        print('*' * 20, 'fine tune encoder for', fine_tune_epochs, 'epochs',
              '*' * 20)
        self.encoder.fine_tune()
        self.optimizer = torch.optim.Adam([
            {
                'params': self.encoder.parameters(),
                'lr': self.ft_encoder_lr
            },
            {
                'params': self.decoder.parameters(),
                'lr': self.ft_decoder_lr
            },
        ])
        self.training(fine_tune_epochs, val_interval, save_path, val_path)
        self.encoder.froze()
        print('*' * 20, 'fine tune encoder complete', '*' * 20)

    def get_params(self):
        """
        模型需要优化的全部参数,此处encoder暂时设计不用训练,故不加参数

        :return:
        """
        return list(self.decoder.parameters())

    def training(self, max_epochs, val_interval, save_path, val_path):
        """
        训练

        :param val_path: 保存验证过程生成句子的路径
        :param save_path: 保存模型的地址
        :param val_interval: 验证的间隔
        :param max_epochs: 最大训练的轮次
        :return:
        """
        print('*' * 20, 'train', '*' * 20)
        for epoch in range(max_epochs):
            self.set_train()

            epoch_loss = 0
            epoch_steps = len(self.train_loader)
            for step, (img, cap,
                       cap_len) in tqdm(enumerate(self.train_loader)):
                # batch_size * 3 * 224 * 224
                img = img.to(DEVICE)
                cap = cap.to(DEVICE)

                self.optimizer.zero_grad()

                features = self.encoder.forward(img)
                outputs = self.decoder.forward(features, cap)

                outputs = pack_padded_sequence(outputs,
                                               cap_len - 1,
                                               batch_first=True)[0]
                targets = pack_padded_sequence(cap[:, 1:],
                                               cap_len - 1,
                                               batch_first=True)[0]
                train_loss = self.loss_fn(outputs, targets)
                epoch_loss += train_loss.item()
                train_loss.backward()
                self.optimizer.step()

            epoch_loss /= epoch_steps
            self.writer.add_scalar('epoch_loss', epoch_loss, epoch)
            print('epoch_loss: {}, epoch: {}'.format(epoch_loss, epoch))
            if (epoch + 1) % val_interval == 0:
                CIDEr = self.validating(epoch, val_path)
                if self.best_CIDEr <= CIDEr:
                    self.best_CIDEr = CIDEr
                    self.save_model(save_path, epoch)

    def save_model(self, save_path, train_epoch):
        """
        保存最好的模型

        :param save_path: 保存模型文件的地址
        :param train_epoch: 当前训练的轮次
        :return:
        """
        model_state_dict = {
            'encoder_state_dict': self.encoder.state_dict(),
            'decoder_state_dict': self.decoder.state_dict(),
            'tran_epoch': train_epoch,
        }
        print('*' * 20, 'save model to: ', save_path, '*' * 20)
        torch.save(model_state_dict, save_path)

    def validating(self, train_epoch, val_path):
        """
        验证

        :param val_path: 保存验证过程生成句子的路径
        :param train_epoch: 当前训练的epoch
        :return:
        """
        print('*' * 20, 'validate', '*' * 20)
        self.set_eval()
        sen_json = []
        with torch.no_grad():
            for val_step, (img, img_id) in tqdm(enumerate(self.val_loader)):
                img = img.to(DEVICE)
                features = self.encoder.forward(img)
                sens, _ = self.decoder.sample(features)
                sen_json.append({'image_id': int(img_id), 'caption': sens[0]})

        with open(val_path, 'w') as f:
            json.dump(sen_json, f)

        result = coco_eval(self.val_cap, val_path)
        scores = {}
        for metric, score in result:
            scores[metric] = score
            self.writer.add_scalar(metric, score, train_epoch)

        return scores['CIDEr']

    def set_train(self):
        self.encoder.train()
        self.decoder.train()

    def set_eval(self):
        self.encoder.eval()
        self.decoder.eval()
Example #6
0
                                          shuffle=True)

OUTPUT_DIM = 10
EPOCH = 10
loss_memory = []
loss_history = []
lr = 0.3
conv_net = CNN(OUTPUT_DIM, lr)

# Training
for e in range(EPOCH):
    correct = 0
    for batch_idx, (data, targets) in enumerate(test_loader):
        print(batch_idx)
        input_data = data.numpy()
        out = conv_net.forward(input_data)
        pred = np.argmax(out, axis=1)
        labels = np.zeros((len(targets), OUTPUT_DIM))
        for i in range(len(targets)):
            if pred[i] == targets[i]:
                correct += 1
            labels[i][targets[i]] = 1
        loss = F.compute_loss(out, labels)
        loss_memory.append(np.sum(loss, axis=0))
        conv_net.backward(labels)
        conv_net.sgd()
    loss_history.append(loss_memory)
    av_loss = np.sum(loss_memory) / len(test_loader.dataset)
    loss_memory = []
    print(
        '\n Training Epoch : {}, Accuracy: ({:.0f}%), Averaged loss : {:.4f} '.