cs231n assignment3 q5 Self-Supervised Learning for Image Classification

news2024/9/24 7:18:37

文章目录

  • 嫌墨迹直接看代码
  • Q5 Self-Supervised Learning for Image Classification
    • compute_train_transform CIFAR10Pair.__getitem__()
      • 题面
      • 解析
      • 代码
      • 输出
    • simclr_loss_naive
      • 题面
      • 解析
      • 代码
      • 输出
    • sim_positive_pairs
      • 题面
      • 解析
      • 代码
      • 输出
    • compute_sim_matrix
      • 题面
      • 解析
      • 代码
      • 输出
    • simclr_loss_vectorized
      • 题面
      • 解析
      • 代码
      • 输出
    • train
      • 题面
      • 解析
      • 代码
      • 输出
  • 结语

嫌墨迹直接看代码

Q5 Self-Supervised Learning for Image Classification

compute_train_transform CIFAR10Pair.getitem()

题面

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

解析

这里就是让我们对图片进行转换,具体的转换步骤在上面都写了,我们只需要查阅相应的api进行调用就好了

代码

def compute_train_transform(seed=123456):
    """
    This function returns a composition of data augmentations to a single training image.
    Complete the following lines. Hint: look at available functions in torchvision.transforms
    """
    random.seed(seed)
    torch.random.manual_seed(seed)

    # Transformation that applies color jitter with brightness=0.4, contrast=0.4, saturation=0.4, and hue=0.1
    color_jitter = transforms.ColorJitter(0.4, 0.4, 0.4, 0.1)

    train_transform = transforms.Compose([
        ##############################################################################
        # TODO: Start of your code.                                                  #
        #                                                                            #
        # Hint: Check out transformation functions defined in torchvision.transforms #
        # The first operation is filled out for you as an example.
        ##############################################################################
        # Step 1: Randomly resize and crop to 32x32.
        transforms.RandomResizedCrop(32),
        # Step 2: Horizontally flip the image with probability 0.5
        transforms.RandomHorizontalFlip(p=0.5),
        # Step 3: With a probability of 0.8, apply color jitter (you can use "color_jitter" defined above.
        transforms.RandomApply(torch.nn.ModuleList([color_jitter]), p=0.8),
        # Step 4: With a probability of 0.2, convert the image to grayscale
        transforms.RandomGrayscale(p=0.2),
        ##############################################################################
        #                               END OF YOUR CODE                             #
        ##############################################################################
        transforms.ToTensor(),
        transforms.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010])])
    return train_transform


def compute_test_transform():
    test_transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010])])
    return test_transform


class CIFAR10Pair(CIFAR10):
    """CIFAR10 Dataset.
    """

    def __getitem__(self, index):
        img, target = self.data[index], self.targets[index]
        img = Image.fromarray(img)

        x_i = None
        x_j = None

        if self.transform is not None:
            ##############################################################################
            # TODO: Start of your code.                                                  #
            #                                                                            #
            # Apply self.transform to the image to produce x_i and x_j in the paper #
            ##############################################################################

            x_i = self.transform(img)
            x_j = self.transform(img)

            ##############################################################################
            #                               END OF YOUR CODE                             #
            ##############################################################################

        if self.target_transform is not None:
            target = self.target_transform(target)

        return x_i, x_j, target

输出

注意这里我不知道为啥本地跑出来的结果是有误差的,但是同样的代码放到colab上跑就没事了,很奇怪我只能说
在这里插入图片描述
在这里插入图片描述

simclr_loss_naive

题面

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
让我们用简单的方法来计算SimCLR的loss

解析

看看上面的题面,一步一步来就好了

代码

def sim(z_i, z_j):
    """Normalized dot product between two vectors.

    Inputs:
    - z_i: 1xD tensor.
    - z_j: 1xD tensor.
    
    Returns:
    - A scalar value that is the normalized dot product between z_i and z_j.
    """
    norm_dot_product = None
    ##############################################################################
    # TODO: Start of your code.                                                  #
    #                                                                            #
    # HINT: torch.linalg.norm might be helpful.                                  #
    ##############################################################################

    # torch.linalg.norm 相对于对一个向量求范数,返回的是一个标量
    norm_dot_product = torch.dot(z_i, z_j) / (torch.linalg.norm(z_i) * torch.linalg.norm(z_j))

    ##############################################################################
    #                               END OF YOUR CODE                             #
    ##############################################################################

    return norm_dot_product


def simclr_loss_naive(out_left, out_right, tau):
    """Compute the contrastive loss L over a batch (naive loop version).
    
    Input:
    - out_left: NxD tensor; output of the projection head g(), left branch in SimCLR model.
    - out_right: NxD tensor; output of the projection head g(), right branch in SimCLR model.
    Each row is a z-vector for an augmented sample in the batch. The same row in out_left and out_right form a positive pair. 
    In other words, (out_left[k], out_right[k]) form a positive pair for all k=0...N-1.
    - tau: scalar value, temperature parameter that determines how fast the exponential increases.
    
    Returns:
    - A scalar value; the total loss across all positive pairs in the batch. See notebook for definition.
    """
    N = out_left.shape[0]  # total number of training examples

    # Concatenate out_left and out_right into a 2*N x D tensor.
    out = torch.cat([out_left, out_right], dim=0)  # [2*N, D]

    total_loss = 0
    for k in range(N):  # loop through each positive pair (k, k+N)
        z_k, z_k_N = out[k], out[k + N]

        ##############################################################################
        # TODO: Start of your code.                                                  #
        #                                                                            #
        # Hint: Compute l(k, k+N) and l(k+N, k).                                     #
        ##############################################################################
        # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

        # 计算 l(k, k+N)
        # 计算左边的分子
        left_numerator = (sim(z_k, z_k_N) / tau).exp()
        # 计算左边的分母中需要进行sim运算的元素
        left_need_sim = out[np.arange(2 * N) != k]
        # 计算左边的分母
        left_denominator = torch.tensor([sim(z_k, z_i) / tau for z_i in left_need_sim]).exp().sum()
        # 计算左边的结果
        left = -(left_numerator / left_denominator).log()

        # 计算 l(k+N, k)
        # 计算右边的分子
        right_numerator = (sim(z_k_N, z_k) / tau).exp()
        # 计算右边的分母中需要进行sim运算的元素
        right_need_sim = out[np.arange(2 * N) != k + N]
        # 计算右边的分母
        right_denominator = torch.tensor([sim(z_k_N, z_i) / tau for z_i in right_need_sim]).exp().sum()
        # 计算右边的结果
        right = -(right_numerator / right_denominator).log()

        total_loss += left + right

        # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****
        ##############################################################################
        #                               END OF YOUR CODE                             #
        ##############################################################################

    # In the end, we need to divide the total loss by 2N, the number of samples in the batch.
    total_loss = total_loss / (2 * N)
    return total_loss

输出

在这里插入图片描述

sim_positive_pairs

题面

在这里插入图片描述
这里跟之前的区别在于之前只需要算两个向量之间的sim,现在算的是两个矩阵之间的sim

解析

看代码注释吧

代码

def sim_positive_pairs(out_left, out_right):
    """Normalized dot product between positive pairs.

    Inputs:
    - out_left: NxD tensor; output of the projection head g(), left branch in SimCLR model.
    - out_right: NxD tensor; output of the projection head g(), right branch in SimCLR model.
    Each row is a z-vector for an augmented sample in the batch.
    The same row in out_left and out_right form a positive pair.
    
    Returns:
    - A Nx1 tensor; each row k is the normalized dot product between out_left[k] and out_right[k].
    """
    pos_pairs = None

    ##############################################################################
    # TODO: Start of your code.                                                  #
    #                                                                            #
    # HINT: torch.linalg.norm might be helpful.                                  #
    ##############################################################################

    # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    # 看看公式,sim 是一个除法,但是可以看做两个除法相乘
    norm_left = out_left / torch.linalg.norm(out_left, dim=1, keepdim=True)
    norm_right = out_right / torch.linalg.norm(out_right, dim=1, keepdim=True)

    pos_pairs = torch.sum(norm_left * norm_right, dim=1, keepdim=True)

    # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    ##############################################################################
    #                               END OF YOUR CODE                             #
    ##############################################################################
    return pos_pairs

输出

在这里插入图片描述

compute_sim_matrix

题面

在这里插入图片描述

这个任务应该就是让我们输出sim_matrix,matrix是一个2N * 2N的矩阵,matrix[i,j]表示sim(i,j)
所以就处理下直接乘以自己的转置就好了

解析

看上面或者看代码,理解一下

代码

def compute_sim_matrix(out):
    """Compute a 2N x 2N matrix of normalized dot products between all pairs of augmented examples in a batch.

    Inputs:
    - out: 2N x D tensor; each row is the z-vector (output of projection head) of a single augmented example.
    There are a total of 2N augmented examples in the batch.
    
    Returns:
    - sim_matrix: 2N x 2N tensor; each element i, j in the matrix is the normalized dot product between out[i] and out[j].
    """
    sim_matrix = None

    ##############################################################################
    # TODO: Start of your code.                                                  #
    ##############################################################################

    # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    out_norm = out / torch.linalg.norm(out, dim=1, keepdim=True)
    sim_matrix = out_norm @ out_norm.T

    # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    ##############################################################################
    #                               END OF YOUR CODE                             #
    ##############################################################################
    return sim_matrix

输出

在这里插入图片描述

simclr_loss_vectorized

题面

在这里插入图片描述
在这里插入图片描述
就是让我们实现序列化的计算loss,按照步骤一步一步来就好了

解析

看注释吧

代码

def simclr_loss_vectorized(out_left, out_right, tau, device='cuda'):
    """Compute the contrastive loss L over a batch (vectorized version). No loops are allowed.
    
    Inputs and output are the same as in simclr_loss_naive.
    """
    N = out_left.shape[0]

    # Concatenate out_left and out_right into a 2*N x D tensor.
    out = torch.cat([out_left, out_right], dim=0)  # [2*N, D]

    # Compute similarity matrix between all pairs of augmented examples in the batch.
    sim_matrix = compute_sim_matrix(out)  # [2*N, 2*N]

    ##############################################################################
    # TODO: Start of your code. Follow the hints.                                #
    ##############################################################################

    # Step 1: Use sim_matrix to compute the denominator value for all augmented samples.
    # Hint: Compute e^{sim / tau} and store into exponential, which should have shape 2N x 2N.
    exponential = (sim_matrix / tau).exp().to(device)

    # This binary mask zeros out terms where k=i.
    mask = (torch.ones_like(exponential, device=device) - torch.eye(2 * N, device=device)).to(device).bool()

    # We apply the binary mask.
    exponential = exponential.masked_select(mask).view(2 * N, -1)  # [2*N, 2*N-1]

    # Hint: Compute the denominator values for all augmented samples. This should be a 2N x 1 vector.
    denom = exponential.sum(dim=1)

    # Step 2: Compute similarity between positive pairs.
    # You can do this in two ways: 
    # Option 1: Extract the corresponding indices from sim_matrix. 
    # Option 2: Use sim_positive_pairs().
    # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    # 计算出所有的正样本对的相似度
    sim_pairs = sim_positive_pairs(out_left, out_right).to(device)
    # 拼接矩阵,因为正样本对是对称的,所以拼接两次
    sim_pairs = torch.cat([sim_pairs, sim_pairs], dim=0)

    # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    # Step 3: Compute the numerator value for all augmented samples.
    numerator = None
    # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    numerator = (sim_pairs / tau).exp()

    # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    # Step 4: Now that you have the numerator and denominator for all augmented samples, compute the total loss.
    loss = None
    # *****START OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    loss = torch.mean(-torch.log(numerator / denom))

    # *****END OF YOUR CODE (DO NOT DELETE/MODIFY THIS LINE)*****

    ##############################################################################
    #                               END OF YOUR CODE                             #
    ##############################################################################

    return loss

输出

在这里插入图片描述

train

题面

在这里插入图片描述
在这里插入图片描述

解析

这里就是让我们将x_i和x_j变成经过处理的gi 和 gj ,然后计算loss就好了

注意一下,这个训练预计要吃5G的显存,如果你的显卡显存不够,量力而行,我的显卡是1060显存3个g,所以为了训练这个模型他额外吃了系统内存,但是降低了训练速度。

代码

输出

训练了差不多一个小时
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结语

这样这个实验就做完了,虽然自己实现了simSLR,但是感觉对这个模型的总体还不是特别清楚,细节部分倒是清楚了,等到时候所有cs231n作业做完再回过头理解一下吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/930919.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

37、springboot 为 spring mvc 提供的自动配置及对自动配置的一些自定义定制(大体思路)

springboot 为 spring mvc 提供的自动配置及对自动配置的一些自定义定制(大体思路) ★ Spring Boot主流支持两个MVC框架: Spring MVC(基于Servlet) Spring WebFlux(基于Reactive,属于响应式AP…

开源双语对话语言模型 ChatGLM-6B 本地私有化部署

本文首发于:https://www.licorne.ink/2023/08/llm-chatglm-6b-local-deploy/ ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型,基于 General Language Model (GLM) 架构,具有 62 亿参数。结合模型量化技术,用户可以在消费级…

人员跌倒检测识别预警

人员跌倒检测识别预警系统通过pythonopencv深度学习网络模型架构,人员跌倒检测识别预警系统实时监测老人的活动状态,通过图像识别和行为分析算法,对老人的姿态、步态等进行检测和识别,一旦系统检测到跌倒事件,立即发出…

Vue2向Vue3过度Vuex核心概念state状态

目录 1 核心概念 - state 状态1.目标2.提供数据3.访问Vuex中的数据4.通过$store访问的语法5.代码实现5.1模板中使用5.2组件逻辑中使用5.3 js文件中使用 2 通过辅助函数 - mapState获取 state中的数据1.第一步:导入mapState (mapState是vuex中的一个函数)2.第二步&am…

Dubbo—流量管控

此任务基于一个简单的线上商城微服务系统演示了 Dubbo 的流量管控能力。 线上商城的架构图如下: 系统由 5 个微服务应用组成: Frontend 商城主页,作为与用户交互的 web 界面,通过调用 User、Detail、Order 等提供用户登录、商品…

为什么使用Nacos而不是Eureka(Nacos和Eureka的区别)

文章目录 前言一、Eureka是什么?二、Nacos是什么?三、Nacos和Eureka的区别3.1 支持的CAP3.2连接方式3.3 服务异常剔除3.4 操作实例方式 总结 前言 为什么如今微服务注册中心用Nacos相对比用Eureka的多了?本文章将介绍他们之间的区别和优缺点…

推荐前 6 名 JavaScript 和 HTML5 游戏引擎

推荐:使用 NSDT场景编辑器 助你快速搭建3D应用场景 事实是,自从引入JavaScript WebGL API以来,现代浏览器具有直观的功能,使它们能够渲染更复杂和复杂的2D和3D图形,而无需依赖第三方插件。 你可以用纯粹的JavaScript开…

Nuxt3打包部署到Linux(node+pm2安装和运行步骤+nginx代理)

最近,我们项目组的工作接近尾声,需要把项目部署上线。由于前端第一次使用Nuxt3框架,后端也是第一次部署Nuxt3项目,所以刚开始出现了很多问题。在我上网搜索很多教程后,得到了基本的流程。 1.服务器安装node.js环境 N…

Linux常用命令_文件搜索命令

文章目录 1. 文件搜索命令find2. 其他搜索命令2.1 文件搜索命令:locate2.2 文件搜索命令:which2.3 文件搜索命令:whereis2.4 文件搜索命令:grep 1. 文件搜索命令find 2. 其他搜索命令 2.1 文件搜索命令:locate 作为f…

c语言练习题30:判断一个数是否为2^n

判断一个数是否为2^n 思路:2^n中只有一个1故可以通过n&(n-1)是否为0来判断。 代码:

Android 之 WindowManager (窗口管理服务)

本节引言: 本节给大家带来的Android给我们提供的系统服务中的——WindowManager(窗口管理服务), 它是显示View的最底层,Toast,Activity,Dialog的底层都用到了这个WindowManager, 他是全局的!该类…

用MFC打开外部程序

在MFC(Microsoft Foundation Classes)中,你可以使用ShellExecute函数来打开Notepad并加载指定的文件。ShellExecute函数是Windows API的一部分,它可以执行与操作系统相关的操作,例如打开文件、运行程序等。 以下是在M…

VBJSON报错:缺少:语句结束

项目中使用JSON库VBJSON时报错: 编译错误:缺少:语句结束 cJSONScript和cStringBuilder报相同的错误,都在第一行: VERSION 1.0 CLASS 研究了半天没啥结果,之前使用这个库的时候没有什么问题,所以判定是当前…

51WORLD李熠:地球克隆计划就像攀登珠峰

提起数字化这个词,相信大家早已耳熟能详。然而数字化世界的意义是什么?它又给我们带来了什么?是让我们的真实世界更加美好?还是让我们沉迷于虚拟世界? 对于以上这些问题,51WORLD创始人兼CEO李熠给出的答案是…

基于Java+SpringBoot+Vue前后端分离医院资源管理系统设计和实现

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…

阿里云将关停代销业务

我是卢松松,点点上面的头像,欢迎关注我哦! 阿里云自从逐渐分拆独立之后,做了很多调整。最近它又做了一个大动作:据DoNews消息,阿里云将会在今年9月30日之前,全面关停代销业务。 这件事实际上…

21.图的应用

目录 一. 最小生成树 (1)普里姆(Prim)算法 (2)克鲁斯卡尔(Kruskal)算法 二. 最短路径 (1)Dijkstra(迪杰斯特拉)算法 (2)Floyd(弗…

Pygame编程(1)初始化和退出模块

初始化和退出模块 pygame使用基础流程 初始化模块设置主屏窗口程序主循环(处理键盘、鼠标、游戏杆、触摸屏等事件)退出模块终止程序 import sys import pygame from pygame.locals import *# 1.初始化模块 pygame.init()# 2.设置主屏窗口 display pyg…

【精品】基于VUE3的 电商详情 图片显示模块

效果 组件 <template><div class"goods-imgs"><div class"imgs-show"><img :src"mainImage" alt"大图" /></div><ul class"img-thumbnail"><li v-for"(item, index) in image…

freertos之任务调度算法

介绍 所谓调度算法&#xff0c;就是怎么确定哪个就绪态的任务可以切换为运行状态。 通过配置文件FreeRTOSConfig.h的三个配置项来配置调度算法&#xff1a;configUSE_PREEMPTION &#xff08;是否抢占&#xff09; configUSE_TIME_SLICING &#xff08;是否轮转&#xff09; c…