精华内容
下载资源
问答
  • PyTorch构造数据集(深度学习计算机视觉)。PyTorch下构造图片数据集。步骤包括:创建合适的文本文件(包含每一张图片的路径与标签)、自定义Dataset的子类datasets,利用DataLoader生成训练和测试数据集。

    构造数据集

    在之前的学习过程中,训练模型用的数据集是pytorch自带的MNIST等,对导入数据集不求甚解。但当上手手势识别项目的时候,我对数据的导入一头雾水,查找到的资料让人“从入门到放弃”。自闭之后,重新研究了构造pytorch数据集的步骤,弄懂了其中一种相对简单的方法。

    储存图片路径与标签的文件

    以txt文件为例,train.txt和test.txt文件中每行都只有一张图片的路径、对应的标签。test.txt文件某片段如下,每行最后的数字是图片的标签。

    test/2/hand1_2_top_seg_4_cropped.png 2
    test/2/hand1_2_top_seg_3_cropped_0_9961.png 2
    test/2/hand1_2_top_seg_3_cropped_0_7789.png 2
    test/2/hand2_2_bot_seg_1_cropped.png 2
    test/3/hand2_3_right_seg_1_cropped.png 3
    test/3/hand5_3_bot_seg_2_cropped.png 3
    

    可以先将图片根据标签储存在不同文件夹,在此基础上,使用python脚本创建这类txt文件。
    (csv等文件亦可,本文以txt为例)

    导入所需的库

    import torch
    import torchvision
    from PIL import Image
    import sys
    

    自定义datasets类

    自定义Dataset的子类——datasets类。
    要之后要用Dataloader所定义的datasets类的话,这个类得拥有三个必要的函数:init、getitem、len。
    注意:这里image_path在txt文件中path前加了’hand_gesture_data/’,保证image_path是正确的相对路径。

    class gesture_datasets(torch.utils.data.Dataset):
        def __init__(self, txt_path, transform=None):
            lines = open(txt_path, 'r')
            imgs = []
            for line in lines:
                line = line.rstrip()
                words = line.split()
                imgs.append((words[0], int(words[1])))
            self.imgs = imgs
            self.transform = transform
        def __getitem__(self, index):
            image_path = 'hand_gesture_data/' + self.imgs[index][0]
            label = self.imgs[index][1]
            img = Image.open(image_path).convert('RGB')
            img = self.transform(img)
            return img, label
        def __len__(self):
            return len(self.imgs)
    

    定义load_data函数

    这里定义了一个函数用于load data,其中将datasets类实例化后,关键在于torch.utils.data.DataLoader的使用。
    txt_path同样是相对路径。使用Dataloader时可以考虑多线程(暂不支持Windows)。

    def load_data_gesture(batch_size, resize=None):
        transform = []
        if resize:
            transform.append(torchvision.transforms.Resize(size=resize))
        transform.append(torchvision.transforms.ToTensor())
        transform = torchvision.transforms.Compose(transform)
        gesture_train = gesture_datasets(txt_path='hand_gesture_data/train/train.txt', transform=transform)
        gesture_test = gesture_datasets(txt_path='hand_gesture_data/test/test.txt', transform=transform)
        num_workers = 0 if sys.platform.startswith('win') else 4
        train_iter = torch.utils.data.DataLoader(gesture_train, batch_size=batch_size, shuffle=True, num_workers=num_workers)
        test_iter = torch.utils.data.DataLoader(gesture_test, batch_size=batch_size, shuffle=False, num_workers=num_workers)
        return train_iter, test_iter
    

    调用函数即可构造

    train_iter, test_iter = load_data_gesture(batch_size=60, resize=(224, 224))
    
    展开全文
  • pytorch时空数据处理4——图像转文本/字幕Image-Captionning(二)pytorch时空数据处理4——图像转文本/字幕Image-Captionning(二) pytorch时空数据处理4——图像转文本/字幕Image-Captionning(二) 书接上文,本...

    pytorch时空数据处理4——图像转文本/字幕Image-Captionning(二)

    书接上文,本篇主要讲解工程代码结构和代码运行。
    代码来源:git

    Dataset

    我正在使用MSCOCO '14数据集。您需要下载训练(13GB)验证(6GB)
    我们将使用安德烈·卡帕西的训练、验证和测试分割方法。这个压缩文件包含标题。您还可以找到FlushT 8K和FlushT 30K数据集的拆分和标题,所以如果MSCOCO对您的计算机来说太大,请随意使用它们来代替MSCOCO。

    Inputs to model

    图像由于我们使用的是预处理编码器,我们需要将图像处理成预处理编码器习惯的形式。
    预训练的ImageNet模型可作为PyTorch的torchvision模块的一部分。论文原文详细说明了我们需要执行的预处理或转换——像素值必须在[0,1]范围内,然后我们必须通过ImageNet图像的RGB通道的平均值和标准偏差对图像进行归一化。

    mean = [0.485, 0.456, 0.406]
    std = [0.229, 0.224, 0.225]
    

    此外,PyTorch遵循NCHW惯例,这意味着通道尺寸©必须在尺寸尺寸之前。我们将调整所有MSCOCO图像的大小为256x256,以保持一致性。因此,馈送到模型的图像必须是维度为N,3,256,256的浮动张量,并且必须通过前述的平均值和标准偏差进行归一化。n为批量大小。字幕字幕是解码器的目标和输入,因为每个单词都用来生成下一个单词。然而,要生成第一个单词,我们需要第零个单词< start >。最后,我们应该预测解码器必须学会预测字幕的结束。这是必要的,因为我们需要知道在推理过程中什么时候停止解码。
    例如:<start> a man holds a football <end>
    因为我们将标题作为固定大小的张量传递,所以我们需要用< pad >标记将标题(自然长度可变)填充到相同的长度。
    <start> a man holds a football <end> <pad> <pad> <pad>…
    此外,我们创建一个word_map,它是语料库中每个单词的索引映射,包括<start>,<end>和<pad>标记。像其他库一样,PyTorch也需要编码为索引的单词来为其查找嵌入或标识其在预测单词分数中的位置。
    例如:9876 1 5 120 1 5406 9877 9878 9878 9878…
    因此,提供给模型的字幕必须是尺寸为N,L的Int张量,其中L是填充长度。

    Caption Lengths

    由于字幕是填充的,因此我们需要跟踪每个字幕的长度。这是实际长度+ 2(对于和标记)。
    字幕长度也很重要,因为您可以使用PyTorch构建动态图形。我们仅处理序列的长度,并且不会在上浪费计算量。
    因此,提供给模型的字幕长度必须是维度N的Int张量。

    Data pipeline

    请参阅utils.py中的create_input_files()。

    1. 这将读取下载的数据并保存以下文件–一个HDF5文件,该文件包含I,3、256、256张量中每个分割的图像,其中I是分割中的图像数。像素值仍在[0,255]范围内,并存储为无符号8位Ints。
    2. 每个分割的JSON文件,其中包含N_c *I编码的字幕列表,其中N_c是每个图像采样的字幕数量。这些标题与HDF5文件中的图像的顺序相同。因此,第i个标题将对应于第i //N_cth个图像。
    3. 每个分割的JSON文件,其中包含N_c * I字幕长度列表。 ith值是ith标题的长度,它对应于i // N_cth图像。
    4. 一个包含word_map(单词到索引的字典)的JSON文件。

    在我们保存这些文件,我们可以选择只使用字幕是短于阈值,并且仓不太频繁的话到标记。
    我们将HDF5文件用于图像,因为我们将在训练/验证期间直接从磁盘读取它们。它们太大了,无法一次放入RAM。但是我们确实将所有字幕及其长度加载到内存中。
    请参阅datasets.py中的CaptionDataset。
    这是PyTorch数据集的子类。它需要定义一个__len__方法,该方法返回数据集的大小,以及一个__getitem__方法,该方法返回第i个图像,标题和标题长度。
    我们从磁盘读取图像,将像素转换为[0,255],然后在此类内对其进行规范化。
    PyTorch DataLoader在train.py中将使用该数据集,以创建一批数据并将其馈送到模型中以进行训练或验证。

    Encoder

    请参阅models.py中的编码器。
    我们使用PyTorch的Torchvision模块中已经提供的经过预训练的ResNet-101。丢弃最后两层(池化层和线性层),因为我们只需要对图像进行编码,而无需对其进行分类。
    我们确实添加了AdaptiveAvgPool2d()层,以将编码大小调整为固定大小。这样就可以将可变大小的图像馈送到编码器。 (但是,我们确实将输入图像的大小调整为256、256,因为我们必须将它们存储为单个张量。)由于我们可能想对编码器进行微调,因此我们添加了fine_tune()方法来启用或禁用计算编码器参数的梯度。我们仅在ResNet中微调卷积块2到4,因为第一个卷积块通常会学到一些非常重要的图像处理基础知识,例如检测直线,边缘,曲线等。我们不会打乱基准特征。

    Attention

    请参阅models.py中的Attention。
    注意网络很简单–它仅由线性层和几个激活组成。
    单独的线性层将解码器的编码图像(展平为N,14 * 14,2048)和隐藏状态(输出)都转换为相同尺寸,即。注意大小。然后添加它们并激活ReLU。第三线性层将此结果转换为1的维度,随后我们应用softmax生成权重alpha。

    Decoder

    请参阅models.py中的DecoderWithAttention。
    此处接收编码器的输出,并将其展平为N,14 * 14,2048尺寸。这很方便,并且避免了多次调整张量的形状。
    我们使用init_hidden_​​state()方法使用编码图像初始化LSTM的隐藏状态和单元状态,该方法使用两个单独的线性层。
    首先,我们通过减少字幕长度来对N个图像和字幕进行排序。这样一来,我们只能处理有效的时间步,即不能处理。
    在这里插入图片描述
    我们可以遍历每个时间步,仅处理有色区域,该区域是该时间步的有效批次大小N_t。通过排序,可以使任何时间步长的顶部N_t与上一步的输出对齐。例如,在第三时间步,我们使用上一步的前5个输出仅处理前5个图像。
    使用PyTorch LSTMCell在for循环中手动执行此迭代,而不是使用PyTorch LSTM在没有循环的情况下自动迭代。这是因为我们需要在每个解码步骤之间执行Attention机制。 LSTMCell是单个时间步操作,而LSTM将连续地在多个时间步上迭代并立即提供所有输出。
    我们使用Attention网络在每个时间步计算权重和注意力加权编码。在论文的第4.2.1节中,他们建议通过滤波器或门传递注意力加权编码。此门是解码器先前隐藏状态的S型激活线性变换。作者指出,这有助于Attention网络将更多的重点放在图像中的对象上。
    我们将过滤后的注意力加权编码与上一个单词的嵌入(开始)连接起来,然后运行LSTMCell生成新的隐藏状态(或输出)。线性层将这种新的隐藏状态转换为词汇表中每个单词的分数,并将其存储起来。
    我们还存储每个时间步长的注意力网络返回的权重。您会很快明白为什么。

    代码

    数据集初始化 create_input_files.py

    为了快速训练和跑通
    选择使用flickr8k数据集,样本量较小,调整和训练都节约时间。

    from utils import create_input_files
    
    if __name__ == '__main__':
        # Create input files (along with word map)
        create_input_files(dataset='flickr8k',
                           karpathy_json_path='/home/wy/docker/resource/cocodataset/dataset_flickr8k.json',
                           image_folder='/home/wy/docker/resource/cocodataset/Flickr8k/Flicker8k_Dataset',
                           captions_per_image=5,
                           min_word_freq=5,
                           output_folder='/home/wy/docker/resource/cocodataset/Flickr8k/data',
                           max_len=50)
    

    训练 train.py

    原文代码pytorch0.4 这里的代码是修改后可以在 pytorch1.0以后版本可以运行的。

    import time
    import torch.backends.cudnn as cudnn
    import torch.optim
    import torch.utils.data
    import torchvision.transforms as transforms
    from torch import nn
    from torch.nn.utils.rnn import pack_padded_sequence
    from models import Encoder, DecoderWithAttention
    from datasets import *
    from utils import *
    from nltk.translate.bleu_score import corpus_bleu
    torch.cuda.set_device(9)
    
    # Data parameters
    data_folder = '/home/wy/docker/resource/cocodataset/Flickr8k/data'  # folder with data files saved by create_input_files.py
    data_name = 'flickr8k_5_cap_per_img_5_min_word_freq'  # base name shared by data files
    
    # Model parameters
    emb_dim = 512  # dimension of word embeddings
    attention_dim = 512  # dimension of attention linear layers
    decoder_dim = 512  # dimension of decoder RNN
    dropout = 0.5
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")  # sets device for model and PyTorch tensors
    cudnn.benchmark = True  # set to true only if inputs to model are fixed size; otherwise lot of computational overhead
    
    # Training parameters
    start_epoch = 0
    epochs = 10  # number of epochs to train for (if early stopping is not triggered)
    epochs_since_improvement = 0  # keeps track of number of epochs since there's been an improvement in validation BLEU
    batch_size = 32
    workers = 1  # for data-loading; right now, only 1 works with h5py
    encoder_lr = 1e-4  # learning rate for encoder if fine-tuning
    decoder_lr = 4e-4  # learning rate for decoder
    grad_clip = 5.  # clip gradients at an absolute value of
    alpha_c = 1.  # regularization parameter for 'doubly stochastic attention', as in the paper
    best_bleu4 = 0.  # BLEU-4 score right now
    print_freq = 100  # print training/validation stats every __ batches
    fine_tune_encoder = False  # fine-tune encoder?
    checkpoint = None  # path to checkpoint, None if none
    
    
    def main():
        """
        Training and validation.
        """
    
        global best_bleu4, epochs_since_improvement, checkpoint, start_epoch, fine_tune_encoder, data_name, word_map
    
        # Read word map
        word_map_file = os.path.join(data_folder, 'WORDMAP_' + data_name + '.json')
        with open(word_map_file, 'r') as j:
            word_map = json.load(j)
    
        # Initialize / load checkpoint
        if checkpoint is None:
            decoder = DecoderWithAttention(attention_dim=attention_dim,
                                           embed_dim=emb_dim,
                                           decoder_dim=decoder_dim,
                                           vocab_size=len(word_map),
                                           dropout=dropout)
            decoder_optimizer = torch.optim.Adam(params=filter(lambda p: p.requires_grad, decoder.parameters()),
                                                 lr=decoder_lr)
            encoder = Encoder()
            encoder.fine_tune(fine_tune_encoder)
            encoder_optimizer = torch.optim.Adam(params=filter(lambda p: p.requires_grad, encoder.parameters()),
                                                 lr=encoder_lr) if fine_tune_encoder else None
    
        else:
            checkpoint = torch.load(checkpoint)
            start_epoch = checkpoint['epoch'] + 1
            epochs_since_improvement = checkpoint['epochs_since_improvement']
            best_bleu4 = checkpoint['bleu-4']
            decoder = checkpoint['decoder']
            decoder_optimizer = checkpoint['decoder_optimizer']
            encoder = checkpoint['encoder']
            encoder_optimizer = checkpoint['encoder_optimizer']
            if fine_tune_encoder is True and encoder_optimizer is None:
                encoder.fine_tune(fine_tune_encoder)
                encoder_optimizer = torch.optim.Adam(params=filter(lambda p: p.requires_grad, encoder.parameters()),
                                                     lr=encoder_lr)
    
        # Move to GPU, if available
        decoder = decoder.to(device)
        encoder = encoder.to(device)
    
        # Loss function
        criterion = nn.CrossEntropyLoss().to(device)
    
        # Custom dataloaders
        normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                         std=[0.229, 0.224, 0.225])
        train_loader = torch.utils.data.DataLoader(
            CaptionDataset(data_folder, data_name, 'TRAIN', transform=transforms.Compose([normalize])),
            batch_size=batch_size, shuffle=True, num_workers=workers, pin_memory=True)
        val_loader = torch.utils.data.DataLoader(
            CaptionDataset(data_folder, data_name, 'VAL', transform=transforms.Compose([normalize])),
            batch_size=batch_size, shuffle=True, num_workers=workers, pin_memory=True)
    
        # Epochs
        for epoch in range(start_epoch, epochs):
    
            # Decay learning rate if there is no improvement for 8 consecutive epochs, and terminate training after 20
            if epochs_since_improvement == 20:
                break
            if epochs_since_improvement > 0 and epochs_since_improvement % 8 == 0:
                adjust_learning_rate(decoder_optimizer, 0.8)
                if fine_tune_encoder:
                    adjust_learning_rate(encoder_optimizer, 0.8)
    
            # One epoch's training
            train(train_loader=train_loader,
                  encoder=encoder,
                  decoder=decoder,
                  criterion=criterion,
                  encoder_optimizer=encoder_optimizer,
                  decoder_optimizer=decoder_optimizer,
                  epoch=epoch)
    
            # One epoch's validation
            recent_bleu4 = validate(val_loader=val_loader,
                                    encoder=encoder,
                                    decoder=decoder,
                                    criterion=criterion)
    
            # Check if there was an improvement
            is_best = recent_bleu4 > best_bleu4
            best_bleu4 = max(recent_bleu4, best_bleu4)
            if not is_best:
                epochs_since_improvement += 1
                print("\nEpochs since last improvement: %d\n" % (epochs_since_improvement,))
            else:
                epochs_since_improvement = 0
    
            # Save checkpoint 保存在utils包里面,全部倒导入的。
            save_checkpoint(data_name, epoch, epochs_since_improvement, encoder, decoder, encoder_optimizer,
                            decoder_optimizer, recent_bleu4, is_best)
    
    
    def train(train_loader, encoder, decoder, criterion, encoder_optimizer, decoder_optimizer, epoch):
        """
        Performs one epoch's training.
    
        :param train_loader: DataLoader for training data
        :param encoder: encoder model
        :param decoder: decoder model
        :param criterion: loss layer
        :param encoder_optimizer: optimizer to update encoder's weights (if fine-tuning)
        :param decoder_optimizer: optimizer to update decoder's weights
        :param epoch: epoch number
        """
    
        decoder.train()  # train mode (dropout and batchnorm is used)
        encoder.train()
        #utils 方法 AverageMeter
        batch_time = AverageMeter()  # forward prop. + back prop. time
        data_time = AverageMeter()  # data loading time
        losses = AverageMeter()  # loss (per word decoded)
        top5accs = AverageMeter()  # top5 accuracy
    
        start = time.time()
    
        # Batches
        for i, (imgs, caps, caplens) in enumerate(train_loader):
            data_time.update(time.time() - start)
    
            # Move to GPU, if available
            imgs = imgs.to(device)
            caps = caps.to(device)
            caplens = caplens.to(device)
    
            # Forward prop.
            imgs = encoder(imgs)
            scores, caps_sorted, decode_lengths, alphas, sort_ind = decoder(imgs, caps, caplens)
    
            # Since we decoded starting with <start>, the targets are all words after <start>, up to <end>
            targets = caps_sorted[:, 1:]
    
            # Remove timesteps that we didn't decode at, or are pads
            # pack_padded_sequence is an easy trick to do this
            scores = pack_padded_sequence(scores, decode_lengths, batch_first=True).data
            targets = pack_padded_sequence(targets, decode_lengths, batch_first=True).data
    
            # Calculate loss
            loss = criterion(scores, targets)
    
            # Add doubly stochastic attention regularization
            loss += alpha_c * ((1. - alphas.sum(dim=1)) ** 2).mean()
    
            # Back prop.
            decoder_optimizer.zero_grad()
            if encoder_optimizer is not None:
                encoder_optimizer.zero_grad()
            loss.backward()
    
            # Clip gradients
            if grad_clip is not None:
                clip_gradient(decoder_optimizer, grad_clip)
                if encoder_optimizer is not None:
                    clip_gradient(encoder_optimizer, grad_clip)
    
            # Update weights
            decoder_optimizer.step()
            if encoder_optimizer is not None:
                encoder_optimizer.step()
    
            # Keep track of metrics
            top5 = accuracy(scores, targets, 5)
            losses.update(loss.item(), sum(decode_lengths))
            top5accs.update(top5, sum(decode_lengths))
            batch_time.update(time.time() - start)
    
            start = time.time()
    
            # Print status
            if i % print_freq == 0:
                print('Epoch: [{0}][{1}/{2}]\t'
                      'Batch Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'
                      'Data Load Time {data_time.val:.3f} ({data_time.avg:.3f})\t'
                      'Loss {loss.val:.4f} ({loss.avg:.4f})\t'
                      'Top-5 Accuracy {top5.val:.3f} ({top5.avg:.3f})'.format(epoch, i, len(train_loader),
                                                                              batch_time=batch_time,
                                                                              data_time=data_time, loss=losses,
                                                                              top5=top5accs))
    
    
    def validate(val_loader, encoder, decoder, criterion):
        """
        Performs one epoch's validation.
    
        :param val_loader: DataLoader for validation data.
        :param encoder: encoder model
        :param decoder: decoder model
        :param criterion: loss layer
        :return: BLEU-4 score
        """
        decoder.eval()  # eval mode (no dropout or batchnorm)
        if encoder is not None:
            encoder.eval()
    
        batch_time = AverageMeter()
        losses = AverageMeter()
        top5accs = AverageMeter()
    
        start = time.time()
    
        references = list()  # references (true captions) for calculating BLEU-4 score
        hypotheses = list()  # hypotheses (predictions)
    
        # explicitly disable gradient calculation to avoid CUDA memory error
        # solves the issue #57
        with torch.no_grad():
            # Batches
            for i, (imgs, caps, caplens, allcaps) in enumerate(val_loader):
    
                # Move to device, if available
                imgs = imgs.to(device)
                caps = caps.to(device)
                caplens = caplens.to(device)
    
                # Forward prop.
                if encoder is not None:
                    imgs = encoder(imgs)
                scores, caps_sorted, decode_lengths, alphas, sort_ind = decoder(imgs, caps, caplens)
    
                # Since we decoded starting with <start>, the targets are all words after <start>, up to <end>
                targets = caps_sorted[:, 1:]
    
                # Remove timesteps that we didn't decode at, or are pads
                # pack_padded_sequence is an easy trick to do this
                scores_copy = scores.clone()
                scores = pack_padded_sequence(scores, decode_lengths, batch_first=True).data
                targets = pack_padded_sequence(targets, decode_lengths, batch_first=True).data
    
                # Calculate loss
                loss = criterion(scores, targets)
    
                # Add doubly stochastic attention regularization
                loss += alpha_c * ((1. - alphas.sum(dim=1)) ** 2).mean()
    
                # Keep track of metrics
                losses.update(loss.item(), sum(decode_lengths))
                top5 = accuracy(scores, targets, 5)
                top5accs.update(top5, sum(decode_lengths))
                batch_time.update(time.time() - start)
    
                start = time.time()
    
                if i % print_freq == 0:
                    print('Validation: [{0}/{1}]\t'
                          'Batch Time {batch_time.val:.3f} ({batch_time.avg:.3f})\t'
                          'Loss {loss.val:.4f} ({loss.avg:.4f})\t'
                          'Top-5 Accuracy {top5.val:.3f} ({top5.avg:.3f})\t'.format(i, len(val_loader), batch_time=batch_time,
                                                                                    loss=losses, top5=top5accs))
    
                # Store references (true captions), and hypothesis (prediction) for each image
                # If for n images, we have n hypotheses, and references a, b, c... for each image, we need -
                # references = [[ref1a, ref1b, ref1c], [ref2a, ref2b], ...], hypotheses = [hyp1, hyp2, ...]
    
                # References
                allcaps = allcaps[sort_ind]  # because images were sorted in the decoder
                for j in range(allcaps.shape[0]):
                    img_caps = allcaps[j].tolist()
                    img_captions = list(
                        map(lambda c: [w for w in c if w not in {word_map['<start>'], word_map['<pad>']}],
                            img_caps))  # remove <start> and pads
                    references.append(img_captions)
    
                # Hypotheses
                _, preds = torch.max(scores_copy, dim=2)
                preds = preds.tolist()
                temp_preds = list()
                for j, p in enumerate(preds):
                    temp_preds.append(preds[j][:decode_lengths[j]])  # remove pads
                preds = temp_preds
                hypotheses.extend(preds)
    
                assert len(references) == len(hypotheses)
    
            # Calculate BLEU-4 scores
            bleu4 = corpus_bleu(references, hypotheses)
    
            print(
                '\n * LOSS - {loss.avg:.3f}, TOP-5 ACCURACY - {top5.avg:.3f}, BLEU-4 - {bleu}\n'.format(
                    loss=losses,
                    top5=top5accs,
                    bleu=bleu4))
    
        return bleu4
    
    
    if __name__ == '__main__':
        main()
    
    

    测试

    使用了原git上提供的预训练模型

    import torch
    import torch.nn.functional as F
    import numpy as np
    import json
    import torchvision.transforms as transforms
    import matplotlib.pyplot as plt
    import matplotlib.cm as cm
    import skimage.transform
    import argparse
    from scipy.misc import imread, imresize
    from PIL import Image
    
    torch.cuda.set_device(9)
    
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    print(device)
    
    def caption_image_beam_search(encoder, decoder, image_path, word_map, beam_size=3):
        """
        Reads an image and captions it with beam search.
    
        :param encoder: encoder model
        :param decoder: decoder model
        :param image_path: path to image
        :param word_map: word map
        :param beam_size: number of sequences to consider at each decode-step
        :return: caption, weights for visualization
        """
    
        k = beam_size
        vocab_size = len(word_map)
    
        # Read image and process
        img = imread(image_path)
        #当为单通道图像时,转化为三通道
        if len(img.shape) == 2:
            img = img[:, :, np.newaxis] #增加纬度
            img = np.concatenate([img, img, img], axis=2) #拼接为三通道
        img = imresize(img, (256, 256))
        img = img.transpose(2, 0, 1)#矩阵转置 通道数放在前面
        img = img / 255.
        img = torch.FloatTensor(img).to(device)
        normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406],
                                         std=[0.229, 0.224, 0.225])
        transform = transforms.Compose([normalize])
        image = transform(img)  # (3, 256, 256)
    
        # Encode
        image = image.unsqueeze(0)  # (1, 3, 256, 256)
        encoder_out = encoder(image)  # (1, enc_image_size, enc_image_size, encoder_dim) 1,14,14,2048
        enc_image_size = encoder_out.size(1)
        print('enc_image_size:',enc_image_size)
        encoder_dim = encoder_out.size(3)
        print('encoder_dim:',encoder_dim)
        # Flatten encoding
        encoder_out = encoder_out.view(1, -1, encoder_dim)  # (1, num_pixels, encoder_dim) 1,196,2048
        #表示了图像的196个区域各自的特征
       # print('encoder_out:',encoder_out)
        num_pixels = encoder_out.size(1)#第二位 196 
        #print('num_pixels:',num_pixels)
        # We'll treat the problem as having a batch size of k
        #print(encoder_out.size())
        encoder_out = encoder_out.expand(k, num_pixels, encoder_dim)  # (k, num_pixels, encoder_dim)1->k纬度扩展,五份特征
        #print(encoder_out.size())
        # Tensor to store top k previous words at each step; now they're just <start>
        k_prev_words = torch.LongTensor([[word_map['<start>']]] * k).to(device)  # (k, 1)
        #print('k_prev_words:',k_prev_words)
        # Tensor to store top k sequences; now they're just <start>
        seqs = k_prev_words  # (k, 1)
    
        # Tensor to store top k sequences' scores; now they're just 0
        top_k_scores = torch.zeros(k, 1).to(device)  # (k, 1)
    
        # Tensor to store top k sequences' alphas; now they're just 1s 这里其实就是存储每个字对应图像上的关注区域,映射在14*14的张量上面
        seqs_alpha = torch.ones(k, 1, enc_image_size, enc_image_size).to(device)  # (k, 1, enc_image_size, enc_image_size)
    
        # Lists to store completed sequences, their alphas and scores
        complete_seqs = list()
        complete_seqs_alpha = list()
        complete_seqs_scores = list()
    
        # Start decoding
        step = 1
        h, c = decoder.init_hidden_state(encoder_out)#h0
        print('h, c',h.size(),c.size())
        # s is a number less than or equal to k, because sequences are removed from this process once they hit <end>
        while True:
    
            embeddings = decoder.embedding(k_prev_words).squeeze(1)  # (s, embed_dim) (5,隐层512)
            print('embeddings',embeddings.size())
            #encode的图片表示 和  隐状态
            awe, alpha = decoder.attention(encoder_out, h)  # (s, encoder_dim), (s, num_pixels)(5,2048(),5,196(attention 存储字对应图像各部分的权重))
            print(' awe, alpha',awe.size(),alpha.size())
            #0/0
            alpha = alpha.view(-1, enc_image_size, enc_image_size)  # (s, enc_image_size, enc_image_size)(5,14,14)
    
            gate = decoder.sigmoid(decoder.f_beta(h))  # gating scalar, (s, encoder_dim)
            
            awe = gate * awe#给特征赋予权重
            
            h, c = decoder.decode_step(torch.cat([embeddings, awe], dim=1), (h, c))  # (s, decoder_dim)输入(512,2048),(512,512)带权重的特征和上一次的lstm输出和细胞状态值
    
            scores = decoder.fc(h)  # (s, vocab_size)
            
            scores = F.log_softmax(scores, dim=1)
            print('scores',scores.size())
            # Add 每一句 含有多少词 更新
            scores = top_k_scores.expand_as(scores) + scores  # (s, vocab_size)
            print('top_k_scores,scores',top_k_scores.size(),scores.size())
            # For the first step, all k points will have the same scores (since same k previous words, h, c)
            if step == 1:
                top_k_scores, top_k_words = scores[0].topk(k, 0, True, True)  # (s)
            else:
                # Unroll and find top scores, and their unrolled indices
                top_k_scores, top_k_words = scores.view(-1).topk(k, 0, True, True)  # (s) 取词,top
            print('top_k_scores,top_k_words',top_k_scores.size(),top_k_words.size())
            # Convert unrolled indices to actual indices of scores
            prev_word_inds = torch.floor_divide(top_k_words, vocab_size)
            #prev_word_inds = top_k_words / vocab_size  # (s)
            next_word_inds = top_k_words % vocab_size  # (s)
            print('top_k_scores,top_k_words,prev_word_inds,next_word_inds',top_k_words,top_k_scores,prev_word_inds,next_word_inds)
            # Add new words to sequences, alphas
            seqs = torch.cat([seqs[prev_word_inds], next_word_inds.unsqueeze(1)], dim=1)  # (s, step+1)#词加一
            seqs_alpha = torch.cat([seqs_alpha[prev_word_inds], alpha[prev_word_inds].unsqueeze(1)],   #词对应图像区域加一
                                   dim=1)  # (s, step+1, enc_image_size, enc_image_size)
    
            # Which sequences are incomplete (didn't reach <end>)? 挑出这次循环完结的 句子
            incomplete_inds = [ind for ind, next_word in enumerate(next_word_inds) if
                               next_word != word_map['<end>']]
            complete_inds = list(set(range(len(next_word_inds))) - set(incomplete_inds))
    
            # Set aside complete sequences 挑出完整序列
            if len(complete_inds) > 0:
                complete_seqs.extend(seqs[complete_inds].tolist()) #追加全部序列
                complete_seqs_alpha.extend(seqs_alpha[complete_inds].tolist())
                complete_seqs_scores.extend(top_k_scores[complete_inds])
            k -= len(complete_inds)  # reduce beam length accordingly
    
            # Proceed with incomplete sequences
            if k == 0:
                break
            #更新参数 只保留未完全序列参数
            seqs = seqs[incomplete_inds]
            seqs_alpha = seqs_alpha[incomplete_inds]
            h = h[prev_word_inds[incomplete_inds]]
            c = c[prev_word_inds[incomplete_inds]]
            encoder_out = encoder_out[prev_word_inds[incomplete_inds]]
            top_k_scores = top_k_scores[incomplete_inds].unsqueeze(1)
            k_prev_words = next_word_inds[incomplete_inds].unsqueeze(1)
    
            # Break if things have been going on too long
            if step > 50:
                break
            step += 1
        #标记 scores分数最高序列作为返回值。
        i = complete_seqs_scores.index(max(complete_seqs_scores))
        seq = complete_seqs[i]
        alphas = complete_seqs_alpha[i]
    
        return seq, alphas
    
    
    def visualize_att(image_path, seq, alphas, rev_word_map, smooth=True):
        """
        Visualizes caption with weights at every word.
    
        Adapted from paper authors' repo: https://github.com/kelvinxu/arctic-captions/blob/master/alpha_visualization.ipynb
    
        :param image_path: path to image that has been captioned
        :param seq: caption
        :param alphas: weights
        :param rev_word_map: reverse word mapping, i.e. ix2word
        :param smooth: smooth weights?
        """
        image = Image.open(image_path)
        image = image.resize([14 * 12, 14 * 12], Image.LANCZOS)
    
        words = [rev_word_map[ind] for ind in seq]
        print(words)
        for t in range(len(words)):
            if t > 50:
                break
            plt.subplot(np.ceil(len(words) / 5.), 5, t + 1)
    
            plt.text(0, 1, '%s' % (words[t]), color='black', backgroundcolor='white', fontsize=12)
            plt.imshow(image)
            current_alpha = alphas[t, :]
            if smooth:
                alpha = skimage.transform.pyramid_expand(current_alpha.numpy(), upscale=12, sigma=8)
            else:
                alpha = skimage.transform.resize(current_alpha.numpy(), [14 * 12, 14 * 12])
            if t == 0:
                plt.imshow(alpha, alpha=0)
            else:
                plt.imshow(alpha, alpha=0.8)
            plt.set_cmap(cm.Greys_r)
            plt.axis('off')
        plt.show()
    
    import scipy
    
    print(scipy.__version__)
    checkpoint = torch.load('./BEST_checkpoint_coco_5_cap_per_img_5_min_word_freq.pth.tar', map_location=str(device))
    decoder = checkpoint['decoder']
    decoder = decoder.to(device)
    decoder.eval()
    encoder = checkpoint['encoder']
    encoder = encoder.to(device)
    encoder.eval()
    
    
    # Load word map (word2ix)
    with open('./WORDMAP_coco_5_cap_per_img_5_min_word_freq.json', 'r') as j:
        word_map = json.load(j)
    rev_word_map = {v: k for k, v in word_map.items()}  # ix2word
    # Encode, decode with attention and beam search
    seq, alphas = caption_image_beam_search(encoder, decoder,'img/q.jpg', word_map,5)
    alphas = torch.FloatTensor(alphas)
    
    # Visualize caption and attention of best sequence
    visualize_att('img/q.jpg', seq, alphas, rev_word_map,True)
    

    这里使用了齐天大圣作为测试图片,输出很有趣,一个长头发的女人在看着相机。
    在这里插入图片描述
    更多细节请查看原文和git。

    展开全文
  • Pytorch官方英文文档:...疫情在家的这段时间,想系统的学习一遍Pytorch基础知识,因为我发现虽然直接Pytorch实战上手比较快,但是关于一些内部的原理知识其实并不是太懂,这样...

    Pytorch官方英文文档:https://pytorch.org/docs/stable/torch.html?
    Pytorch中文文档:https://pytorch-cn.readthedocs.io/zh/latest/

    1. 写在前面

    疫情在家的这段时间,系统的学习一遍Pytorch基础知识,因为我发现虽然直接Pytorch实战上手比较快,但是关于一些内部的原理知识其实并不是太懂,这样学习起来感觉很不踏实, 对Pytorch的使用依然是模模糊糊, 跟着人家的代码用Pytorch玩神经网络还行,也能读懂,但自己亲手做的时候,直接无从下手,啥也想不起来, 我觉得我这种情况就不是对于某个程序练得不熟了,而是对Pytorch本身在自己的脑海根本没有形成一个概念框架,不知道它内部运行原理和逻辑,所以自己写的时候没法形成一个代码逻辑,就无从下手。 这种情况即使背过人家这个程序,那也只是某个程序而已,不能说会Pytorch, 并且这种背程序的思想本身就很可怕, 所以我还是习惯学习知识先有框架(至少先知道有啥东西)然后再通过实战(各个东西具体咋用)来填充这个框架。 而这个系列的目的就是在脑海中先建一个Pytorch的基本框架出来, 学习知识,知其然,知其所以然才更有意思 😉

    今天是该系列的第一篇, 我们直接从Pytorch最基础的开始,这部分首先会整理Pytorch中数据结构张量的概念和创建方法,然后整理张量的各种操作,最后通过前面所学玩一个简单的线性回归。

    注意,本系列都默认已经安装了Cuda,搭建好了Pytorch环境,如果你电脑是Windows,并且没有装Pytorch,那么巧了, 我之前写过一篇怎么搭建环境,可以先看看 Pytorch入门+实战系列一:Windows下的Pytorch环境手把手搭建 😉

    大纲如下:

    • 张量的简介与创建(张量及各种创建方式)

    • 张量的基本操作(张量的切分,拼接,索引,变换,数学运算)

    • 玩一个简单的线性回归模型

    • 总结梳理

    Ok, let’s go!

    2. 张量的简介与创建

    这部分内容介绍pytorch中的数据结构——Tensor,Tensor是PyTorch中最基础的概念,其参与了整个运算过程,主要介绍张量的概念和属性,如data, device, dtype等,并介绍tensor的基本创建方法,如直接创建、依数值创建和依概率分布创建等。

    2.1 张量的简介

    1. 张量的基本概念
      张量其实是一个多维数组,它是标量、向量、矩阵的高维拓展

      在这里插入图片描述

    2. Tensor与Variable
      在Pytorch0.4.0版本之后其实Variable已经并入Tensor, 但是Variable这个数据类型的了解,对于理解张量来说很有帮助, 这到底是个什么呢?

      Variable是torch.autograd中的数据类型。
      1
      Variable有下面的5个属性:

      • data: 被包装的Tensor
      • grad: data的梯度
      • grad_fn: fn表示function的意思,记录我么创建的创建张量时用到的方法,比如说加法,乘法,这个操作在求导过程需要用到,Tensor的Function, 是自动求导的关键
      • requires_grad: 指示是否需要梯度, 有的不需要梯度
      • is_leaf: 指示是否是叶子节点(张量)

      这些属性都是为了张量的自动求导而设置的, 从Pytorch0.4.0版开始,Variable并入了Tensor, 看看张量里面的属性:
      在这里插入图片描述
      可以发现,如今版本里面的Tensor共有8个属性,上面四个与数据本身相关,下面四个与梯度求导相关。 其中有五个是Variable并入过来的, 这些含义就不解释了, 而还有三个属性没有说:

      • dtype: 张量的数据类型, 如torch.FloatTensor, torch.cuda.FloatTensor, 用的最多的一般是float32和int64(torch.long)
      • shape: 张量的形状, 如(64, 3, 224, 224)
      • device: 张量所在的设备, GPU/CPU, 张量放在GPU上才能使用加速。

      知道了什么是张量,那么如何创建张量呢?

    2.2 张量的创建

    1. 直接创建张量
      torch.Tensor(): 功能: 从data创建Tensor

      在这里插入图片描述
      这里的data,就是我们的数据,可以是list,也可以是numpy。 dtype这个是指明数据类型, 默认与data的一致。 device是指明所在的设备, requires_grad是是否需要梯度, 在搭建神经网络的时候需要求导的那些参数这里要设置为true。 pin_memory是否存于锁页内存,这个设置为False就可以。下面就具体代码演示:

      arr = np.ones((3, 3))
      print('ndarry的数据类型:', arr.dtype)
      
      t = torch.tensor(arr, device='cuda')
      print(t)
      
      ## 结果如下:
      ndarry的数据类型: float64
      tensor([[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]], device='cuda:0', dtype=torch.float64)
      
    2. 通过numpy数组来创建
      torch.from_numpy(ndarry): 从numpy创建tensor
      注意:这个创建的Tensor与原ndarray共享内存, 当修改其中一个数据的时候,另一个也会被改动。
      在这里插入图片描述
      下面具体看代码演示(共享内存):

      arr = np.array([[1, 2, 3], [4, 5, 6]])
      t = torch.from_numpy(arr)
      
      print(arr, '\n',t)
      arr[0, 0] = 0
      print('*' * 10)
      print(arr, '\n',t)
      t[1, 1] = 100
      print('*' * 10)
      print(arr, '\n',t)
      
      ## 结果:
      [[1 2 3]
       [4 5 6]] 
       tensor([[1, 2, 3],
              [4, 5, 6]], dtype=torch.int32)
      **********
      [[0 2 3]
       [4 5 6]] 
       tensor([[0, 2, 3],
              [4, 5, 6]], dtype=torch.int32)
      **********
      [[  0   2   3]
       [  4 100   6]] 
       tensor([[  0,   2,   3],
              [  4, 100,   6]], dtype=torch.int32)
      
    3. 依据数值创建
      torch.zeros(): 依size创建全0的张量

      在这里插入图片描述
      这些参数都比较好理解,layout这个是内存中的布局形式, 一般采用默认就可以。 这个out,表示输出张量,就是再把这个张量赋值给别的一个张量,但是这两个张量时一样的,指的同一个内存地址。看代码:

      out_t = torch.tensor([1])
      t = torch.zeros((3, 3), out=out_t)
      
      print(out_t, '\n', t)
      print(id(t), id(out_t), id(t) == id(out_t))   # 这个看内存地址
      
      ## 结果:
      tensor([[0, 0, 0],
              [0, 0, 0],
              [0, 0, 0]]) 
       tensor([[0, 0, 0],
              [0, 0, 0],
              [0, 0, 0]])
      2575719258696 2575719258696 True
      

      torch.zeros_like(input, dtype=None, layout=None, device=None, requires_grad=False) : 这个是创建与input同形状的全0张量

      t = torch.zeros_like(out_t)   # 这里的input要是个张量
      print(t)
      
      tensor([[0, 0, 0],
              [0, 0, 0],
              [0, 0, 0]])
      

      除了全0张量, 还可以创建全1张量, 用法和上面一样,torch.ones(), torch.ones_like(), 还可以自定义数值张量:torch.full(), torch.full_like()
      在这里插入图片描述
      这里的fill_value就是要填充的值。

      t = torch.full((3,3), 10)
      tensor([[10., 10., 10.],
              [10., 10., 10.],
              [10., 10., 10.]])
      

      torch.arange(): 创建等差的1维张量,数值区间[start, end), 注意这是右边开,取不到最后的那个数。

      在这里插入图片描述
      这个和numpy的差不多,这里的step表示的步长。

      t = torch.arange(2, 10, 2)  # tensor([2, 4, 6, 8])
      

      torch.linspace(): 创建均分的1维张量, 数值区间[start, end] 注意这里都是闭区间,和上面的区分。

      在这里插入图片描述
      这里是右闭, 能取到最后的值,并且这里的steps是数列的长度而不是步长。

      t = torch.linspace(2, 10, 5)   # tensor([2, 4, 6, 8, 10])
      
      # 那么如果不是那么正好呢? 步长应该是多少?
      t = torch.linspace(2, 10, 6)   # tensor([2, 3.6, 5.2, 6.8, 8.4, 10])
      
      # 这个步长是怎么算的?  (end-start) / (steps-1)
      

      除了创建均分数列,还可以创建对数均分数列:

      在这里插入图片描述
      这里的base表示以什么为底。

      最后一个方法就是torch.eye(): 创建单位对角矩阵, 默认是方阵
      在这里插入图片描述
      n, m分别是矩阵的行数和列数。

    4. 依概率分布创建张量
      torch.normal():生成正态分布(高斯分布), 这个使用的比较多
      在这里插入图片描述
      mean是均值,std是标准差。 但是这个地方要注意, 根据mean和std,分别各有两种取值,所以这里会有四种模式:

      • mean为标量, std为标量
      • mean为标量, std为张量
      • mean为张量, std为标量
      • mean为张量,std为张量


      这个看代码来的直接:

       # 第一种模式 - 均值是标量, 方差是标量 - 此时产生的是一个分布, 从这一个分部种抽样相应的个数,所以这个必须指定size,也就是抽取多少个数
          t_normal = torch.normal(0, 1, size=(4,))
          print(t_normal)     # 来自同一个分布
      
          # 第二种模式 - 均值是标量, 方差是张量 - 此时会根据方差的形状大小,产生同样多个分布,每一个分布的均值都是那个标量
          std = torch.arange(1, 5, dtype=torch.float)
          print(std.dtype)
          t_normal2 = torch.normal(1, std)
          print(t_normal2)        # 也产生来四个数,但是这四个数分别来自四个不同的正态分布,这些分布均值相等
      
          # 第三种模式 - 均值是张量,方差是标量 - 此时也会根据均值的形状大小,产生同样多个方差相同的分布,从这几个分布中分别取一个值作为结果
          mean = torch.arange(1, 5, dtype=torch.float)
          t_normal3 = torch.normal(mean, 1)
          print(t_normal3)     # 来自不同的分布,但分布里面方差相等
      
          # 第四种模式 - 均值是张量, 方差是张量 - 此时需要均值的个数和方差的个数一样多,分别产生这么多个正太分布,从这里面抽取一个值
          mean = torch.arange(1, 5, dtype=torch.float)
          std = torch.arange(1, 5, dtype=torch.float)
          t_normal4 = torch.normal(mean, std)
          print(t_normal4)          # 来自不同的分布,各自有自己的均值和方差
      
      

      下面一个是标准正态分布:torch.randn(), torch.randn_like()
      在这里插入图片描述


      生成均匀分布:torch.rand(), rand_like() 在[0,1)生成均匀分布
      torch.randint(), torch.randint_like(): 区间[low,hight)生成整数均匀分布

      在这里插入图片描述
      下面看最后两个:
      torch.randperm(n): 生成从0 - n-1的随机排列, n是张量的长度, 经常用来生成一个乱序索引。
      torch.bernoulli(input): 以input为概率,生成伯努利分布(0-1分布,两点分布), input: 概率值

      在这里插入图片描述

    3. 张量的操作

    这次整理张量的基本操作,比如张量的拼接,切分,索引和变换以及数学运算等,并基于所学习的知识,实现线性回归模型。

    3.1 张量的基本操作

    1. 张量的拼接

      • torch.cat(tensors, dim=0, out=None): 将张量按维度dim进行拼接, tensors表示张量序列, dim要拼接的维度
      • torch.stack(tensors, dim=0, out=None): 在新创建的维度dim上进行拼接, tensors表示张量序列, dim要拼接的维度

      这是啥意思, stack会新创建一个维度,然后完成拼接。还是看代码:

      # 张量的拼接
      t = torch.ones((2, 3))
      print(t)
      
      t_0 = torch.cat([t, t], dim=0)       # 行拼接
      t_1 = torch.cat([t, t], dim=1)    # 列拼接
      print(t_0, t_0.shape)
      print(t_1, t_1.shape)
      
      # 结果:
      tensor([[1., 1., 1.],
          [1., 1., 1.]])
      tensor([[1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.],
          [1., 1., 1.]]) torch.Size([4, 3])
      tensor([[1., 1., 1., 1., 1., 1.],
          [1., 1., 1., 1., 1., 1.]]) torch.Size([2, 6])
      

      .cat是在原来的基础上根据行和列,进行拼接, 我发现一个问题,就是浮点数类型拼接才可以,long类型拼接会报错。 下面我们看看.stack方法:

      t_stack = torch.stack([t,t,t], dim=0)
      print(t_stack)
      print(t_stack.shape)
      
      t_stack1 = torch.stack([t, t, t], dim=1)
      print(t_stack1)
      print(t_stack1.shape)
      
      ## 结果:
      tensor([[[1., 1., 1.],
               [1., 1., 1.]],
      
              [[1., 1., 1.],
               [1., 1., 1.]],
      
              [[1., 1., 1.],
               [1., 1., 1.]]])
      torch.Size([3, 2, 3])
      tensor([[[1., 1., 1.],
               [1., 1., 1.],
               [1., 1., 1.]],
      
              [[1., 1., 1.],
               [1., 1., 1.],
               [1., 1., 1.]]])
      torch.Size([2, 3, 3])
      

      .stack是根据给定的维度新增了一个新的维度,在这个新维度上进行拼接,这个.stack与其说是从新维度上拼接,不太好理解,其实是新加了一个维度Z轴,只不过dim=0和dim=1的视角不同罢了。 dim=0的时候,是横向看,dim=1是纵向看。

      所以这两个使用的时候要小心,看好了究竟是在原来的维度上拼接到一块,还是从新维度上拼接到一块。

    2. 张量的切分
      torch.chunk(input, chunks, dim=0): 将张量按维度dim进行平均切分, 返回值是张量列表,注意,如果不能整除, 最后一份张量小于其他张量。 chunks代表要切分的维度。 下面看一下代码实现:

      a = torch.ones((2, 7))  # 7
      list_of_tensors = torch.chunk(a, dim=1, chunks=3)   # 第一个维度切成三块, 那么应该是(2,3), (2,3), (2,1)  因为7不能整除3,所以每一份应该向上取整,最后不够的有多少算多少
      print(list_of_tensors)
      for idx, t in enumerate(list_of_tensors):
          print("第{}个张量:{}, shape is {}".format(idx+1, t, t.shape))
       
      ## 结果:
      (tensor([[1., 1., 1.],
              [1., 1., 1.]]), tensor([[1., 1., 1.],
              [1., 1., 1.]]), tensor([[1.],
              [1.]]))1个张量:tensor([[1., 1., 1.],
              [1., 1., 1.]]), shape is torch.Size([2, 3])2个张量:tensor([[1., 1., 1.],
              [1., 1., 1.]]), shape is torch.Size([2, 3])3个张量:tensor([[1.],
              [1.]]), shape is torch.Size([2, 1])
      

      torch.split(tensor, split_size_or_sections, dim=0): 这个也是将张量按维度dim切分,但是这个更加强大, 可以指定切分的长度, split_size_or_sections为int时表示每一份的长度, 为list时,按list元素切分

      # split
      t = torch.ones((2, 5))
      
      list_of_tensors = torch.split(t, [2, 1, 2], dim=1)  # [2 , 1, 2], 这个要保证这个list的大小正好是那个维度的总大小,这样才能切
      for idx, t in enumerate(list_of_tensors):
          print("第{}个张量:{}, shape is {}".format(idx+1, t, t.shape))
      
      ## 结果1个张量:tensor([[1., 1.],
              [1., 1.]]), shape is torch.Size([2, 2])2个张量:tensor([[1.],
              [1.]]), shape is torch.Size([2, 1])3个张量:tensor([[1., 1.],
              [1., 1.]]), shape is torch.Size([2, 2])
      

      所以切分,也有两个函数,.chunk和.split。 .chunk切分的规则就是提供张量,切分的维度和几份, 比如三份, 先计算每一份的大小,也就是
      这个维度的长度除以三,然后上取整,就开始沿着这个维度切,最后不够一份大小的,也就那样了。 所以长度为7的这个维度,3块,每块7/3上取整
      是3, 然后第一块3,第二块是3,第三块1。这样切
      .split这个函数的功能更加强大,它可以指定每一份的长度,只要传入一个列表即可,或者也有一个整数,表示每一份的长度,这个就根据每一份的长度先切着, 看看能切几块算几块。 不过列表的那个好使,可以自己指定每一块的长度,但是注意一下,这个长度的总和必须是维度的那个总长度才用办法切。

    3. 张量的索引
      torch.index_select(input, dim, index, out=None): 在维度dim上,按index索引数据,返回值,以index索引数据拼接的张量。

      t = torch.randint(0, 9, size=(3, 3))     #  从0-8随机产生数组成3*3的矩阵
      print(t)
      idx = torch.tensor([0, 2], dtype=torch.long)   # 这里的类型注意一下,要是long类型
      t_select = torch.index_select(t, dim=1, index=idx)  #第0列和第2列拼接返回
      print(t_select)
      
      ## 结果:
      tensor([[3, 7, 3],
          [4, 3, 7],
          [5, 8, 0]])
      tensor([[3, 3],
          [4, 7],
          [5, 0]])
      

      torch.masked_select(input, mask, out=None): 按mask中的True进行索引,返回值:一维张量。 input表示要索引的张量, mask表示与input同形状的布尔类型的张量。 这种情况在选择符合某些特定条件的元素的时候非常好使, 注意这个是返回一维的张量。下面看代码:

      mask = t.ge(5)   # le表示<=5, ge表示>=5 gt >5  lt <5
      print("mask: \n", mask)
      t_select1 = torch.masked_select(t, mask)   # 选出t中大于5的元素
      print(t_select1)
      
      ## 结果:
      mask: 
       tensor([[False,  True, False],
          [False, False,  True],
          [ True,  True, False]])
      tensor([7, 7, 5, 8])
      

      所以张量的索引,有两种方式:.index_select和.masked_select

      • .index_select: 按照索引查找 需要先指定一个Tensor的索引量,然后指定类型是long的
      • .masked_select: 就是按照值的条件进行查找,需要先指定条件作为mask
    4. 张量的变换
      torch.reshape(input, shape): 变换张量的形状,这个很常用,input表示要变换的张量,shape表示新张量的形状。 但注意,当张量在内存中是连续时, 新张量与input共享数据内存

      # torch.reshape
      t = torch.randperm(8)       # randperm是随机排列的一个函数
      print(t)
      
      t_reshape = torch.reshape(t, (-1, 2, 2))    # -1的话就是根据后面那两个参数,计算出-1这个值,然后再转
      print("t:{}\nt_reshape:\n{}".format(t, t_reshape))
      
      t[0] = 1024
      print("t:{}\nt_reshape:\n{}".format(t, t_reshape))
      print("t.data 内存地址:{}".format(id(t.data)))
      print("t_reshape.data 内存地址:{}".format(id(t_reshape.data))) # 这个注意一下,两个是共内存的
      
      ## 结果:
      tensor([2, 4, 3, 1, 5, 6, 7, 0])
      t:tensor([2, 4, 3, 1, 5, 6, 7, 0])
      t_reshape:
      tensor([[[2, 4],
               [3, 1]],
      
              [[5, 6],
               [7, 0]]])
      t:tensor([1024,    4,    3,    1,    5,    6,    7,    0])
      t_reshape:
      tensor([[[1024,    4],
               [   3,    1]],
      
              [[   5,    6],
               [   7,    0]]])
      t.data 内存地址:1556953167336
      t_reshape.data 内存地址:1556953167336
      

      上面这两个是共内存的, 一个改变另一个也会改变。这个要注意一下。

      torch.transpose(input, dim0, dim1): 交换张量的两个维度, 矩阵的转置常用, 在图像的预处理中常用, dim0要交换的维度, dim1表示要交换的问题

      # torch.transpose
      t = torch.rand((2, 3, 4))      # 产生0-1之间的随机数
      print(t)
      t_transpose = torch.transpose(t, dim0=0, dim1=2)    # c*h*w     h*w*c, 这表示第0维和第2维进行交换
      print("t shape:{}\nt_transpose shape: {}".format(t.shape, t_transpose.shape))
      
      ## 结果:
      tensor([[[0.7480, 0.5601, 0.1674, 0.3333],
               [0.4648, 0.6332, 0.7692, 0.2147],
               [0.7815, 0.8644, 0.6052, 0.3650]],
      
              [[0.2536, 0.1642, 0.2833, 0.3858],
               [0.8337, 0.6173, 0.3923, 0.1878],
               [0.8375, 0.2109, 0.4282, 0.4974]]])
      t shape:torch.Size([2, 3, 4])
      t_transpose shape: torch.Size([4, 3, 2])
      tensor([[[0.7480, 0.2536],
               [0.4648, 0.8337],
               [0.7815, 0.8375]],
      
              [[0.5601, 0.1642],
               [0.6332, 0.6173],
               [0.8644, 0.2109]],
      
              [[0.1674, 0.2833],
               [0.7692, 0.3923],
               [0.6052, 0.4282]],
      
              [[0.3333, 0.3858],
               [0.2147, 0.1878],
               [0.3650, 0.4974]]])
      

      torch.t(input): 2维张量的转置, 对矩阵而言,相当于torch.transpose(inpuot, 0,1)

      torch.squeeze(input, dim=None, out=None): 压缩长度为1的维度, dim若为None,移除所有长度为1的轴,若指定维度,当且仅当该轴长度为1时可以被移除

      # torch.squeeze
      t = torch.rand((1, 2, 3, 1))
      t_sq = torch.squeeze(t)
      t_0 = torch.squeeze(t, dim=0)
      t_1 = torch.squeeze(t, dim=1)
      print(t.shape)        # torch.Size([1, 2, 3, 1])
      print(t_sq.shape)     # torch.Size([2, 3])
      print(t_0.shape)     # torch.Size([2, 3, 1])
      print(t_1.shape)     # torch.Size([1, 2, 3, 1])
      

      torch.unsqueeze(input, dim, out=None): 依据dim扩展维度

    3.2 张量的数学运算

    3.2.1 标量运算

    Pytorch中提供了丰富的数学运算,可以分为三大类: 加减乘除, 对数指数幂函数,三角函数
    在这里插入图片描述
    这里重点演示一下加法这个函数, 因为这个函数有一个小细节:
    torch.add(input, alpha=1, other, out=None): 逐元素计算input+alpha * other。 注意人家这里有个alpha,叫做乘项因子。类似权重的个东西。 这个东西让计算变得更加简洁, 比如线性回归我们知道有个y = wx + b, 在这里直接一行代码torch.add(b, w, x)就搞定。 类似的还有两个方法:
    torch.addcdiv(input, value=1, tensor1, tensor2, out=None): 这个实现了
    o u t i = i n p u t i + v a l u e × t e n s o r 1 i t e n s o r 2 i out_i = input_i + value\times\frac{tensor1_i}{tensor2_i} outi=inputi+value×tensor2itensor1i
    torch.addcmul(input, value=1, tensor1, tensor2, out=None): 这个实现了
    o u t i = i n p u t i + v a l u e × t e n s o r 1 i × t e n s o r 2 i out_i = input_i + value\times tensor1_i\times tensor2_i outi=inputi+value×tensor1i×tensor2i
    这个在优化的时候经常会用到。

    t_0 = torch.randn((3, 3))
    t_1 = torch.ones_like(t_0)
    t_add = torch.add(t_0, 10, t_1)
    
    print("t_0:\n{}\nt_1:\n{}\nt_add_10:\n{}".format(t_0, t_1, t_add))
    
    ## 结果:
    t_0:
    tensor([[-0.4133,  1.4492, -0.1619],
            [-0.4508,  1.2543,  0.2360],
            [ 1.0054,  1.2767,  0.9953]])
    t_1:
    tensor([[1., 1., 1.],
            [1., 1., 1.],
            [1., 1., 1.]])
    t_add_10:
    tensor([[ 9.5867, 11.4492,  9.8381],
            [ 9.5492, 11.2543, 10.2360],
            [11.0054, 11.2767, 10.9953]])
    

    3.2.2 向量运算

    向量运算符只在一个特定轴上运算,将一个向量映射到一个标量或者另外一个向量。

    #统计值
    
    a = torch.arange(1,10).float()
    print(torch.sum(a))
    print(torch.mean(a))
    print(torch.max(a))
    print(torch.min(a))
    print(torch.prod(a)) #累乘
    print(torch.std(a))  #标准差
    print(torch.var(a))  #方差
    print(torch.median(a)) #中位数
    

    cum扫描

    #cum扫描
    a = torch.arange(1,10)
    
    print(torch.cumsum(a,0))    # 累加
    print(torch.cumprod(a,0))    # 累乘
    print(torch.cummax(a,0).values)
    print(torch.cummax(a,0).indices)
    print(torch.cummin(a,0))
    

    张量排序

    #torch.sort和torch.topk可以对张量排序
    a = torch.tensor([[9,7,8],[1,3,2],[5,6,4]]).float()
    print(torch.topk(a,2,dim = 0),"\n")
    print(torch.topk(a,2,dim = 1),"\n")
    print(torch.sort(a,dim = 1),"\n")
    
    #利用torch.topk可以在Pytorch中实现KNN算法
    

    3.2.4 矩阵运算

    矩阵必须是二维的。类似torch.tensor([1,2,3])这样的不是矩阵。

    矩阵运算包括:矩阵乘法,矩阵转置,矩阵逆,矩阵求迹,矩阵范数,矩阵行列式,矩阵求特征值,矩阵分解等运算。

    1. 矩阵乘法

      #矩阵乘法
      a = torch.tensor([[1,2],[3,4]])
      b = torch.tensor([[2,0],[0,2]])
      print(a@b)  #等价于torch.matmul(a,b) 或 torch.mm(a,b)
      
    2. 转置

      #矩阵转置
      a = torch.tensor([[1.0,2],[3,4]])
      print(a.t())
      
    3. 矩阵求逆

      #矩阵逆,必须为浮点类型
      a = torch.tensor([[1.0,2],[3,4]])
      print(torch.inverse(a))
      
    4. 矩阵求迹

      #矩阵求trace
      a = torch.tensor([[1.0,2],[3,4]])
      print(torch.trace(a))
      
    5. 求范数和行列式

      #矩阵求范数
      a = torch.tensor([[1.0,2],[3,4]])
      print(torch.norm(a))
      
      #矩阵行列式
      a = torch.tensor([[1.0,2],[3,4]])
      print(torch.det(a))
      
    6. 特征值和特征向量

      #矩阵特征值和特征向量
      a = torch.tensor([[1.0,2],[-5,4]],dtype = torch.float)
      print(torch.eig(a,eigenvectors=True))
      
      #两个特征值分别是 -2.5+2.7839j, 2.5-2.7839j 
      
    7. QR分解

      #矩阵QR分解, 将一个方阵分解为一个正交矩阵q和上三角矩阵r
      #QR分解实际上是对矩阵a实施Schmidt正交化得到q
      
      a  = torch.tensor([[1.0,2.0],[3.0,4.0]])
      q,r = torch.qr(a)
      print(q,"\n")
      print(r,"\n")
      print(q@r)
      
    8. SVD分解

      #矩阵svd分解
      #svd分解可以将任意一个矩阵分解为一个正交矩阵u,一个对角阵s和一个正交矩阵v.t()的乘积
      #svd常用于矩阵压缩和降维
      a=torch.tensor([[1.0,2.0],[3.0,4.0],[5.0,6.0]])
      
      u,s,v = torch.svd(a)
      
      print(u,"\n")
      print(s,"\n")
      print(v,"\n")
      
      print(u@torch.diag(s)@v.t())
      
      #利用svd分解可以在Pytorch中实现主成分分析降维
      
      

    下面基于上面的这些方法玩一个线性回归模型。

    4. 搭建一个线性回归模型

    线性回归是分析一个变量与另外一(多)个变量之间关系的方法。 因变量是y, 自变量是x, 关系线性:
    y = w × x + b y = w\times x + b y=w×x+b
    任务就是求解w,b。

    我们的求解步骤:

    1. 确定模型: Model -> y = wx + b
    2. 选择损失函数: 这里用MSE : 1 m ∑ i = 1 m ( y i − y ^ i ) 2 \frac{1}{m} \sum_{i=1}^{m}\left(y_{i}-\hat{y}_{i}\right)^2 m1i=1m(yiy^i)2
    3. 求解梯度并更新w, b
      w = w − L R × w . g r a d b = b − L R × w . g r a d \begin{aligned} &w=w-L R\times w. g r a d\\ &b=b-L R\times w. g r a d \end{aligned} w=wLR×w.gradb=bLR×w.grad

    这就是我上面说的叫做代码逻辑的一种思路, 写代码往往习惯先有一个这样的一种思路,然后再去写代码的时候,就比较容易了。 而如果不系统的学一遍Pytorch, 一上来直接上那种复杂的CNN, LSTM这种,往往这些代码逻辑不好形成,因为好多细节我们根本就不知道。 所以这次学习先从最简单的线性回归开始,然后慢慢的到复杂的那种网络。下面我们开始写一个线性回归模型:

    # 首先我们得有训练样本X,Y, 这里我们随机生成
    x = torch.rand(20, 1) * 10
    y = 2 * x + (5 + torch.randn(20, 1))
    
    # 构建线性回归函数的参数
    w = torch.randn((1), requires_grad=True)
    b = torch.zeros((1), requires_grad=True)   # 这俩都需要求梯度
    
    for iteration in range(100):
    	# 前向传播
    	wx = torch.mul(w, x)
    	y_pred = torch.add(wx, b)
    	
    	# 计算loss
    	loss = (0.5 * (y-y_pred)**2).mean()
    	
    	# 反向传播
    	loss.backward()
    	
    	# 更新参数
    	b.data.sub_(lr * b.grad)    # 这种_的加法操作时从自身减,相当于-=
    	w.data.sub_(lr * w.grad)
    
    	# 梯度清零
    	w.grad.data.zero_()
    	b.grad.data.zero_()
    
    print(w.data, b.data)
    

    我们看一下结果:

    在这里插入图片描述

    5. 总结

    今天的学习内容结束, 下面简单的梳理一遍,其实小东西还是挺多的, 首先我们从Pytorch最基本的数据结构开始,认识了张量到底是个什么东西,说白了就是个多维数组,然后张量本身有很多的属性, 有关于数据本身的data, dtype, shape, dtype, 也有关于求导的requires_grad, grad, grad_fn, is_leaf。 然后学习了张量的创建方法, 比如直接创建,从数组创建,数值创建,按照概率创建等。 这里面涉及到了很多的创建函数tensor(), from_numpy(), ones(), zeros(), eye(), full(), arange(), linspace(), normal(), randn(), rand(), randint(), randperm()等等吧。

    接着就是张量的操作部分, 有基本操作和数学运算, 基本操作部分有张量的拼接两个函数(.cat, .stack), 张量的切分两个函数(.chunk, .split), 张量的转置(.reshape, .transpose, .t), 张量的索引两个函数(.index_select, .masked_select)。 数学运算部分,也是很多数学函数,有加减乘除的,指数底数幂函数的,三角函数的很多。

    最后基于上面的所学完成了一个简单的线性回归。 下面以一张思维导图把这一篇文章的内容拎起来:
    在这里插入图片描述

    这次整理了很多的函数,每个函数的用法不同,具体用法先不用刻意记住,先知道哪些函数具体完成什么功能,到时候用的时,边查边用,慢慢的多练才能熟。

    Ok, 下一次学习Pytorch的动态图机制以及自动求导机制, 然后基于前面的这两篇再玩一个逻辑回归, 我们从最简单的模型开始 😉

    代码链接:
    链接:https://pan.baidu.com/s/1YPmOtLCjsfu8KDGGgJ09Ug
    提取码:u8ti
    复制这段内容后打开百度网盘手机App,操作更方便哦–来自百度网盘超级会员V1的分享

    展开全文
  • Pytorch数据采样器

    千次阅读 2020-06-08 15:55:27
    num_replicas=None, rank=None, shuffle=True, seed=0)[source] 源代码 采样器的返回值是一个索引列表,用于在训练集中查找训练样本,一般总的元素数是数据集的长度。 class torch.utils.data.Sampler(data_source)...

    目录

    class torch.utils.data.Sampler(data_source)[source]

    class torch.utils.data.SequentialSampler(data_source)[source]

    class torch.utils.data.RandomSampler(data_source, replacement=False, num_samples=None)[source]

    class torch.utils.data.SubsetRandomSampler(indices)[source]

    class torch.utils.data.WeightedRandomSampler(weights, num_samples, replacement=True)[source]

    class torch.utils.data.BatchSampler(sampler, batch_size, drop_last)[source]

    class torch.utils.data.distributed.DistributedSampler(dataset, num_replicas=None, rank=None, shuffle=True, seed=0)[source]

    源代码


    采样器的返回值是一个索引列表,用于在训练集中查找训练样本,一般总的元素数是数据集的长度。

    class torch.utils.data.Sampler(data_source)[source]

    所有采样器的基类。

    每个采样器的子类必须提供一个__iter__()方法,提供一个数据集元素指数上进行迭代的方法,并且__len__()方法返回迭代器的长度。

    注意:

    在Dataloader中__len__()方法不是严格需要的,但是在任何包含Datalaoder长度的计算中都需要。

    class torch.utils.data.SequentialSampler(data_source)[source]

    顺序的采样元素,通常以相同的顺序。

    参数:

    data_source (Dataset) – 数据集的来源

    class torch.utils.data.RandomSampler(data_source, replacement=False, num_samples=None)[source]

    随机采样元素。如果不能重复采样,样本来自打乱后的数据集。如果可以重复采样,使用者可以指定需要的样本数num_samples。

    参数:

    • data_source (Dataset) – 需要采样的数据集

    • replacement (bool) – 是否可以重复采样

    • num_samples (int) – 需要采样的样本数,默认为数据集的长度,参数仅仅在可以重复为真实设置。

    class torch.utils.data.SubsetRandomSampler(indices)[source]

    从给定的指数列表中随机采样,不可以重复采样。

    参数:

    • indices (sequence) – 指数的序列

    class torch.utils.data.WeightedRandomSampler(weights, num_samples, replacement=True)[source]

    [0,..,len(weights)-1]中以给定的概率(权重)进行采样元素。

    参数:

    • weights (sequence) – 一个权重序列,不必要不需要加起来是1。

    • num_samples (int) – 需要采样的样本数。

    • replacement (bool) – 如果为真的话,样本可以进行重复采样。如果为假,不可以进行重复采样,这意味着当一个样本指数来自某行时,对那行不能再一次进行采样。

    Example

    >>> list(WeightedRandomSampler([0.1, 0.9, 0.4, 0.7, 3.0, 0.6], 5, replacement=True))
    [4, 4, 1, 4, 5]
    >>> list(WeightedRandomSampler([0.9, 0.4, 0.05, 0.2, 0.3, 0.1], 5, replacement=False))
    [0, 1, 4, 3, 2]

    class torch.utils.data.BatchSampler(sampler, batch_size, drop_last)[source]

    包裹另一个采样器来产生指数的mini-batch。

    参数:

    • sampler (Sampler or Iterable) – 基采样器,任何用__len__()实现的可迭代采样器都可以。

    • batch_size (int) – min-batch的尺寸。

    • drop_last (bool) – 如果为真,采样器将会下降到最后一个batch,如果它的尺寸比batch_size小的话。

    Example:

    >>> list(BatchSampler(SequentialSampler(range(10)), batch_size=3, drop_last=False))
    [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
    >>> list(BatchSampler(SequentialSampler(range(10)), batch_size=3, drop_last=True))
    [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

    class torch.utils.data.distributed.DistributedSampler(dataset, num_replicas=None, rank=None, shuffle=True, seed=0)[source]

    Sampler that restricts data loading to a subset of the dataset.

    限制数据载入成为数据集子集的采样器。

    It is especially useful in conjunction with torch.nn.parallel.DistributedDataParallel. In such a case, each process can pass a :class`~torch.utils.data.DistributedSampler` instance as a DataLoader sampler, and load a subset of the original dataset that is exclusive to it.

    torch.nn.parallel.DistributedDataParallel一起使用很有必要。在这种情况下,每个过程能通过一个类torch.utils.data.DistributedSampler实例作为一个DataLoader采样器,并且载入除了它的原始数据集的子集。

    注意

    数据集假定是一个固定的尺寸。

    参数:

    • dataset – 用来进行采样的数据集。

    • num_replicas (int, optional) – 参与到分布式训练的进程数。默认情况下,rank来自当前的分布式组。

    • rank (int, optional) – num_replicas内当前进程的rank。默认情况下,rank来自当前分布式的组。

    • shuffle (bool, optional) – 如果是真的话,采样器将会打乱指数。

    • seed (int, optional) – 如果打乱的话,用来打乱采样器的随机种子。在分布式group的所有进程上数量将是一样的。默认是0。

    注意:

    在分布式模式中称为:meth`set_epoch(epoch) <set_epoch>`方法,在每个epoch开始的时候。在创建DataLoader之前,迭代器有必要通过多epochs来进行适当的打乱。否则,总是使用相同的顺序。

    例:

    >>> sampler = DistributedSampler(dataset) if is_distributed else None
    >>> loader = DataLoader(dataset, shuffle=(sampler is None),
    ...                     sampler=sampler)
    >>> for epoch in range(start_epoch, n_epochs):
    ...     if is_distributed:
    ...         sampler.set_epoch(epoch)
    ...     train(loader)

    源代码

    import torch
    from torch._six import int_classes as _int_classes
    
    
    [docs]class Sampler(object):
        r"""Base class for all Samplers.
    
        Every Sampler subclass has to provide an :meth:`__iter__` method, providing a
        way to iterate over indices of dataset elements, and a :meth:`__len__` method
        that returns the length of the returned iterators.
    
        .. note:: The :meth:`__len__` method isn't strictly required by
                  :class:`~torch.utils.data.DataLoader`, but is expected in any
                  calculation involving the length of a :class:`~torch.utils.data.DataLoader`.
        """
    
        def __init__(self, data_source):
            pass
    
        def __iter__(self):
            raise NotImplementedError
    
    
        # NOTE [ Lack of Default `__len__` in Python Abstract Base Classes ]
        #
        # Many times we have an abstract class representing a collection/iterable of
        # data, e.g., `torch.utils.data.Sampler`, with its subclasses optionally
        # implementing a `__len__` method. In such cases, we must make sure to not
        # provide a default implementation, because both straightforward default
        # implementations have their issues:
        #
        #   + `return NotImplemented`:
        #     Calling `len(subclass_instance)` raises:
        #       TypeError: 'NotImplementedType' object cannot be interpreted as an integer
        #
        #   + `raise NotImplementedError()`:
        #     This prevents triggering some fallback behavior. E.g., the built-in
        #     `list(X)` tries to call `len(X)` first, and executes a different code
        #     path if the method is not found or `NotImplemented` is returned, while
        #     raising an `NotImplementedError` will propagate and and make the call
        #     fail where it could have use `__iter__` to complete the call.
        #
        # Thus, the only two sensible things to do are
        #
        #   + **not** provide a default `__len__`.
        #
        #   + raise a `TypeError` instead, which is what Python uses when users call
        #     a method that is not defined on an object.
        #     (@ssnl verifies that this works on at least Python 3.7.)
    
    
    [docs]class SequentialSampler(Sampler):
        r"""Samples elements sequentially, always in the same order.
    
        Arguments:
            data_source (Dataset): dataset to sample from
        """
    
        def __init__(self, data_source):
            self.data_source = data_source
    
        def __iter__(self):
            return iter(range(len(self.data_source)))
    
        def __len__(self):
            return len(self.data_source)
    
    
    
    [docs]class RandomSampler(Sampler):
        r"""Samples elements randomly. If without replacement, then sample from a shuffled dataset.
        If with replacement, then user can specify :attr:`num_samples` to draw.
    
        Arguments:
            data_source (Dataset): dataset to sample from
            replacement (bool): samples are drawn with replacement if ``True``, default=``False``
            num_samples (int): number of samples to draw, default=`len(dataset)`. This argument
                is supposed to be specified only when `replacement` is ``True``.
        """
    
        def __init__(self, data_source, replacement=False, num_samples=None):
            self.data_source = data_source
            self.replacement = replacement
            self._num_samples = num_samples
    
            if not isinstance(self.replacement, bool):
                raise TypeError("replacement should be a boolean value, but got "
                                "replacement={}".format(self.replacement))
    
            if self._num_samples is not None and not replacement:
                raise ValueError("With replacement=False, num_samples should not be specified, "
                                 "since a random permute will be performed.")
    
            if not isinstance(self.num_samples, int) or self.num_samples <= 0:
                raise ValueError("num_samples should be a positive integer "
                                 "value, but got num_samples={}".format(self.num_samples))
    
        @property
        def num_samples(self):
            # dataset size might change at runtime
            if self._num_samples is None:
                return len(self.data_source)
            return self._num_samples
    
        def __iter__(self):
            n = len(self.data_source)
            if self.replacement:
                return iter(torch.randint(high=n, size=(self.num_samples,), dtype=torch.int64).tolist())
            return iter(torch.randperm(n).tolist())
    
        def __len__(self):
            return self.num_samples
    
    
    
    [docs]class SubsetRandomSampler(Sampler):
        r"""Samples elements randomly from a given list of indices, without replacement.
    
        Arguments:
            indices (sequence): a sequence of indices
        """
    
        def __init__(self, indices):
            self.indices = indices
    
        def __iter__(self):
            return (self.indices[i] for i in torch.randperm(len(self.indices)))
    
        def __len__(self):
            return len(self.indices)
    
    
    
    [docs]class WeightedRandomSampler(Sampler):
        r"""Samples elements from ``[0,..,len(weights)-1]`` with given probabilities (weights).
    
        Args:
            weights (sequence)   : a sequence of weights, not necessary summing up to one
            num_samples (int): number of samples to draw
            replacement (bool): if ``True``, samples are drawn with replacement.
                If not, they are drawn without replacement, which means that when a
                sample index is drawn for a row, it cannot be drawn again for that row.
    
        Example:
            >>> list(WeightedRandomSampler([0.1, 0.9, 0.4, 0.7, 3.0, 0.6], 5, replacement=True))
            [4, 4, 1, 4, 5]
            >>> list(WeightedRandomSampler([0.9, 0.4, 0.05, 0.2, 0.3, 0.1], 5, replacement=False))
            [0, 1, 4, 3, 2]
        """
    
        def __init__(self, weights, num_samples, replacement=True):
            if not isinstance(num_samples, _int_classes) or isinstance(num_samples, bool) or \
                    num_samples <= 0:
                raise ValueError("num_samples should be a positive integer "
                                 "value, but got num_samples={}".format(num_samples))
            if not isinstance(replacement, bool):
                raise ValueError("replacement should be a boolean value, but got "
                                 "replacement={}".format(replacement))
            self.weights = torch.as_tensor(weights, dtype=torch.double)
            self.num_samples = num_samples
            self.replacement = replacement
    
        def __iter__(self):
            return iter(torch.multinomial(self.weights, self.num_samples, self.replacement).tolist())
    
        def __len__(self):
            return self.num_samples
    
    
    
    [docs]class BatchSampler(Sampler):
        r"""Wraps another sampler to yield a mini-batch of indices.
    
        Args:
            sampler (Sampler or Iterable): Base sampler. Can be any iterable object
                with ``__len__`` implemented.
            batch_size (int): Size of mini-batch.
            drop_last (bool): If ``True``, the sampler will drop the last batch if
                its size would be less than ``batch_size``
    
        Example:
            >>> list(BatchSampler(SequentialSampler(range(10)), batch_size=3, drop_last=False))
            [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
            >>> list(BatchSampler(SequentialSampler(range(10)), batch_size=3, drop_last=True))
            [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
        """
    
        def __init__(self, sampler, batch_size, drop_last):
            # Since collections.abc.Iterable does not check for `__getitem__`, which
            # is one way for an object to be an iterable, we don't do an `isinstance`
            # check here.
            if not isinstance(batch_size, _int_classes) or isinstance(batch_size, bool) or \
                    batch_size <= 0:
                raise ValueError("batch_size should be a positive integer value, "
                                 "but got batch_size={}".format(batch_size))
            if not isinstance(drop_last, bool):
                raise ValueError("drop_last should be a boolean value, but got "
                                 "drop_last={}".format(drop_last))
            self.sampler = sampler
            self.batch_size = batch_size
            self.drop_last = drop_last
    
        def __iter__(self):
            batch = []
            for idx in self.sampler:
                batch.append(idx)
                if len(batch) == self.batch_size:
                    yield batch
                    batch = []
            if len(batch) > 0 and not self.drop_last:
                yield batch
    
        def __len__(self):
            if self.drop_last:
                return len(self.sampler) // self.batch_size
            else:
                return (len(self.sampler) + self.batch_size - 1) // self.batch_size

     

     

    展开全文
  • 也就是说每10次epoch就更改学习率见其应用到optim中,学习率的策略采用poly,其他策略可以在我的收藏里面查找 net.train() 进行模型的训练 inputs, labels = sample_batched['image'], sample_batched['...
  • 这是胡佩云的PyTorch实现。 在使用此代码库时,我们使用(并建议使用) Python 3.6+来减少痛苦(加上Python 3.6具有非常酷的功能)。 注意如果使用此代码,请务必引用Peiyun的CVPR论文和此仓库! 此代码在WIDER ...
  • 详解pytorch 中的数据加载过程,并详细解释Dataset和DataLoader的使用方法
  • Pytorch

    千次阅读 2019-06-11 09:31:24
    Apex:Pytorch分布式数据并行DDP [另一种官方实现] python -m torch.distributed.launch --nproc_per_node=NUM_GPUS main_amp.py args... pytorch使用torch.utils.bottleneck预测程序瓶颈 torch.utils....
  • 今天小编就为大家分享一篇PyTorch中Tensor的数据统计示例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • PyTorch提供了许多工具来简化数据加载过程,并使代码更具可读性。 在本教程中,我们将看到如何从有价值的数据集中加载和预处理/增强数据。 要运行本教程,请确保已安装以下软件包: scikit-i...
  • Dataset和DataLoader都是Pytorch里面读取数据的工具。现在对这两种工具做一个概括和总结。 1.Dataset 一个例子: # 导入需要的包 import torch import torch.utils.data.dataset as Dataset import numpy as np ...
  • Pytorch数据加载的分析

    千次阅读 2020-07-09 22:39:18
    由于图片数据为0~255,部分数值变换可以使用cv2.LUT()查找表直接映射,避免多次计算数值。 尽量提前做好数据处理,减少预处理步骤。 (2) DALI 如果加速还不满意的话,最后还有一个大招,DALLI库,大力出奇迹,极度...
  • 1.55.自定义数据 1.55.1.数据传递机制 我们首先回顾识别手写数字的程序: ... Dataset = torchvision.datasets.MNIST(root='./mnist/', train=True, transform=transform, download=True,) dataloader = torch.utils...
  • 基于Pytorch的MNIST数据集的预处理

    千次阅读 2019-05-18 09:49:18
    基于Pytorch的MNIST数据集的预处理 第一步:了解MNIST数据集 MNIST数据集是一个手写体数据集,一共60000张图片,所有的图片都是28×28的,下载数据集的地址:数据集官网。这个数据集由四部分组成,分别是: train-...
  • pytorch

    2020-10-18 21:01:08
    Pytorch中的数据处理 train_dataset = CustomDataset(train_data_path)#进行数据集的封装 自定义的类,继承Dataset class CustomDataset(Dataset): “”“默认使用 List 存储数据”"" def init(self, fp): self.file...
  • 本文以 官方文档 为依据,不涉及大量的源码推导,仅在必要处展示示例代码,意在帮助各位读者理清楚Pytorch数据加载机制,以根据自己的意志实现项目中的数据加载需求。 目录一、DataLoader,Dataset,Sampler之间...
  • Pytorch从本地获取数据

    千次阅读 2020-03-10 11:31:04
    Pytorch从本地获取数据集 在学习pytorch的过程中需要从MNIST获取数据集,然而下载是让人头疼的事,从网上寻找数据资源比较便捷 获取到的数据如何在pytorch中加载呢 1 下载数据集 ...2. 从本地进行数据加载 ...
  • Pytorch使用DataLoader批量加载数据

    千次阅读 2020-06-11 10:18:12
    在进行模型训练时,需要把数据按照固定的形式分批次投喂给模型,在PyTorch中通过torch.utils.data库的`DataLoader`完成分批次返回数据。构造DataLoader首先需要一个`Dataset`数据源,Dataset完成数据的读取并可以...
  • 深度之眼学习心得 ...数据数据收集---img,label 数据分割---train,valid,test 数据读取---DataLoader(Sampler(生成索引),Dataset(根据索引拿到img and label)) 数据预处理---transforms Da...
  • PyTorch

    2019-07-08 22:18:18
    数据加载到PyTorch张量,按batch加载 构建模型 训练模型 提取预训练特征 自定义Pytorch数据数据集处理 常见错误 AttributeError: ‘module’ object has no attribute ‘empty’ 在138机器上执行命令...
  • Tensor是pytorch中所应用的一种数据结构,torch.Tensor是存储和变换数据的主要工具。 1.1.1 创建Tensor 创建Tensor import torch #导入Pytorch x= torch.empty(5,3) #创建一个5*3的随机Tensor print(x) 输出: ...
  • PyTorch中为VoxCeleb1数据集实现VGGVox。 火车 pip install -r requirements.txt python3 train.py --dir ./data/ 用--dir指定数据目录 笔记 81.79%Top-1和93.17 Top-5测试装置的准确性,非常令人满意。 在中查找...
  • pytorch加载pascal&&coco数据

    千次阅读 2018-11-21 13:43:40
    amp;&amp;coco数据集,本篇我们将介绍pytorch如何加载 ...pascal数据集的数据源是jpg图片,便签是xml文件,而pytorch运算使用的数据是Tensor。因此我们的目标是将jpg和xml文件转化为可供程序运算使用...
  • pytorch 查看tensor中的数据类型

    千次阅读 2019-05-05 11:22:02
    import torch x=torch.Tensor([1,2]) print('x: ',x) print('type(x): ',type(x)) print('x.dtype: ',x....所以想查看tensor中数据的类型,就使用 tensor.dtype 想查看变量的类型,就使用 type(变量)  
  • 本人按照github上的过程进行编译pytorch(C++)的时候,一直遇到问题,一开始以为是clone代码不完整的问题,后来仔细查找报错信息,发现是pytorch源码中的一个函数跟cuda的函数名冲突了导致(本人环境cuda10.1 按照...
  • Pytorch:EDSR 生成训练数据的方法 引言 Winter is coming 正文 pytorch提供的DataLoader 是用来包装你的数据的工具. 所以你要将自己的 (numpy array 或其他) 数据形式装换成 Tensor, 然后再放进这个包装器中. ...
  • 今天尝试使用多显卡训练PyTorch代码。 不过训练时报错,查找代码发现此前曾设定单一GPU训练,如下。 将其注释掉,再次运行,又发现报错。 查找资料发现训练模型所使用的显卡必须要包括主卡,而我在设置训练GPU时...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,537
精华内容 1,414
关键字:

pytorch查找数据