分类: R语言

  • R语言矩阵乘法

    矩阵乘法用%*%符号。矩阵乘法的A%*%B和B%*%A结果是不同的,没有交换律。

    A <- matrix(1:4,nrow=2 ,byrow=T)
    B <- matrix(5:8,nrow=2 ,byrow=T)
    A %*% B
    
  • R语言ReLU函数的实现

    ReLU可以作为神经网络的激活函数,当数值小于0的时候,返回0,当数值大于0的时候返回本身。

    ReLU <- function(x) {  
      return(sapply(x, function(val) max(0, val)))  
    }  
    
    x <- c(-1, 1, 2)  
    y <- ReLU(x)  
    plot(x, y)
    
  • R语言sigmoid函数的作图

    sigmoid函数是平滑的阶跃函数。

    sigmoid <- function(x){
      return(1/(1+exp(-x)))
    }
    x <- c(-1.0,1.0,2.0)
    y <- sigmoid(x)
    plot(x,y)
    
  • R语言阶跃函数的转换和作图

    阶跃函数(Step Function)是一种在某些点上发生突变的函数,通常用于数学、工程和计算机科学中。最常见的阶跃函数是Heaviside阶跃函数,它在某个特定点(通常是0)发生变化。

    x <- c(-1, 1, 2, 2, 0)
    x
    y <- x > 0
    y
    y <- as.integer(y)
    y
    plot(x,y)
    

  • torch和luz做深度学习预测

    library(torch)
    library(luz)
    
    # input dimensionality (number of input features)
    # 定义输入的特征维度为 3
    d_in <- 3
    # 定义训练数据的样本数量为 1000
    # number of observations in training set
    n <- 1000
    
    # 生成一个形状为 (1000, 3) 的随机张量,作为输入特征
    x <- torch_randn(n, d_in)
    # 定义一个系数向量,用于线性映射
    coefs <- c(0.2, -1.3, -0.5)
    # 是生成的目标标签(模拟真实结果)
    # 通过将 x 和 coefs 进行矩阵乘法后
    # 加上形状为 (1000, 1) 的随机噪声生成
    y <- x$matmul(coefs)$unsqueeze(2) + torch_randn(n, 1)
    
    # 将张量 x 和 y 封装成一个数据集对象
    ds <- tensor_dataset(x, y)
    
    # 创建用于训练的批量加载器
    # 表示每次从数据集中加载 100 个样本
    # 在加载数据时数据会被打乱
    dl <- dataloader(ds, batch_size = 100, shuffle = TRUE)
    
    # dimensionality of hidden layer
    d_hidden <- 32   # 隐藏层的维度
    # output dimensionality (number of predicted features)
    d_out <- 1   # 输出层的维度
    
    # 定义神经网络模块
    net <- nn_module(
      initialize = function(d_in, d_hidden, d_out) {
        # 三个层组成的序列
        self$net <- nn_sequential(
          nn_linear(d_in, d_hidden),   # 线性全连接层
          nn_relu(),   # 激活函数
          nn_linear(d_hidden, d_out)   # 线性全连接层
        )
      },
      # 向前传播方法
      forward = function(x) {
        self$net(x)
      }
    )
    
    # 结果赋值给fitted
    fitted <- net %>%
    # 设置损失函数和优化器
      setup(loss = nn_mse_loss(), optimizer = optim_adam) %>%
      # 设置超参数
      set_hparams(
        d_in = d_in,   # 输入层维度
        d_hidden = d_hidden, d_out = d_out   # 隐藏层神经元数量和输出层维度
      ) %>%
      fit(dl, epochs = 200)   # 使用数据加载器,200个epoch
    
    # 从数据集的完整索引中随机抽取60%的索引作为训练集的索引
    train_ids <- sample(1:length(ds), size = 0.6 * length(ds))
    # 从剩余的索引中(即非训练集的部分)随机抽取20%的索引作为验证集的索引
    valid_ids <- sample(
      setdiff(1:length(ds), train_ids),
      size = 0.2 * length(ds)
    )
    # 将训练集和验证集的索引从完整索引中排除,剩下的索引作为测试集的索引
    test_ids <- setdiff(
      1:length(ds),
      union(train_ids, valid_ids)
    )
    
    # 创建基于训练集索引的子数据集
    train_ds <- dataset_subset(ds, indices = train_ids)
    # 基于验证集索引的数据集
    valid_ds <- dataset_subset(ds, indices = valid_ids)
    # 测试集索引的子数据集
    test_ds <- dataset_subset(ds, indices = test_ids)
    
    # 为训练集创建数据加载器,指定批量大小为100,并启用数据打乱(shuffle)
    train_dl <- dataloader(train_ds,
      batch_size = 100, shuffle = TRUE
    )
    # 为验证集创建数据加载器,指定批量大小为100
    valid_dl <- dataloader(valid_ds, batch_size = 100)
    # 为测试集创建数据加载器,指定批量大小为100
    test_dl <- dataloader(test_ds, batch_size = 100)
    fitted <- net %>%
    # 函数用于设置模型的基本配置
      setup(
        loss = nn_mse_loss(),   # 指定使用均方误差 (MSE) 作为损失函数
        optimizer = optim_adam,   # 选择使用 Adam 优化器
        metrics = list(luz_metric_mae())   # 评估指标使用平均绝对误差 (MAE)
      ) %>%
      set_hparams(   # 设置模型的超参数
        d_in = d_in,   # 输入维度
        d_hidden = d_hidden, d_out = d_out   # 隐藏层维度和输出维度
      ) %>%
    #   训练模型,训练加载,200个周期,验证集
      fit(train_dl, epochs = 200, valid_data = valid_dl)
    # fitted 在测试数据集 test_dl 上进行评估
    fitted %>% evaluate(test_dl)
    
    # 另一个训练
    fitted <- net %>%
      setup(
        loss = nn_mse_loss(),
        optimizer = optim_adam,
        metrics = list(luz_metric_mae())
      ) %>%
      set_hparams(d_in = d_in,
                  d_hidden = d_hidden,
                  d_out = d_out) %>%
      fit(
        train_dl,
        epochs = 200,
        valid_data = valid_dl,
        callbacks = list(   # 回调函数提供训练过程中的特殊功能
        # 模型检查点功能,自动保存性能最佳的模型,保存在./modoels/
          luz_callback_model_checkpoint(path = "./models/",
                                        # 只保存最佳模型
                                        save_best_only = TRUE),
          # 提前停止功能,当验证集性能在 10 轮内没有改善时停止训练,避免过拟合
          luz_callback_early_stopping(patience = 10)
        )
      )
    # 使用训练好的模型(fitted)对测试数据集 (test_dl) 进行预测
    fitted %>% predict(test_dl)
    
    
  • torch获取MNIST数据集并初始化

    # 获取 mnist 的数据集
    ds <- mnist_dataset(
      # 存放目录
      root = dir,
      # 下载训练集
      train = TRUE, # default
      download = TRUE,   # 如果不存在,则下载
      # 将图像数据转换为张量
      transform = function(x) {
        x %>% transform_to_tensor() 
      }
    )
    # 从数据集中取出第一条数据(图像和标签)
    first <- ds[1]
    # 打印第一张图片的形状和对应的标签
    cat("Image shape: ", first$x$shape, " Label: ", first$y, "\n")
    
    
    展开/折叠结果
    Processing...
    Done!
    
    Image shape:  1 28 28  Label:  6 
    
    length(dl)
    
    展开/折叠结果
    [1] 1875
    
    first_batch <- dl %>%   # 链式操作
      # obtain an iterator for this dataloader
      dataloader_make_iter() %>%   # 生成迭代器
      dataloader_next()   # 从迭代器中读取下一批数据
    
    dim(first_batch$x)   # 检查x的维度
    dim(first_batch$y)   # 检查y的维度
    
    展开/折叠结果
    [1] 32  1 28 28
    [1] 32
    
  • torch读取数据

    library(torch)
    library(palmerpenguins)
    library(dplyr)
    
    # 以摘要形式展示数据集的结构和内容
    penguins %>% glimpse()
    
    展开/折叠结果
    Rows: 344
    Columns: 8
    $ species            Adelie, Adelie, Adelie, Adelie, Adelie…
    $ island             Torgersen, Torgersen, Torgersen, Torge…
    $ bill_length_mm     39.1, 39.5, 40.3, NA, 36.7, 39.3, 38.9…
    $ bill_depth_mm      18.7, 17.4, 18.0, NA, 19.3, 20.6, 17.8…
    $ flipper_length_mm  181, 186, 195, NA, 193, 190, 181, 195,…
    $ body_mass_g        3750, 3800, 3250, NA, 3450, 3650, 3625…
    $ sex                male, female, female, NA, female, male…
    $ year               2007, 2007, 2007, 2007, 2007, 2007, 20…
    
    # 数据框转换为张量
    penguins_dataset <- dataset(
      name = "penguins_dataset()",
      # 初始化
      initialize = function(df) {
        # 去除NA
        df <- na.omit(df)
        # 取数据框第3到第6列,转换为矩阵,然后进一步转换为PyTorch张量
        self$x <- as.matrix(df[, 3:6]) %>% torch_tensor()
        # 将species列(物种信息)转换为数值型(类别编码),再转为PyTorch长整型张量
        self$y <- torch_tensor(
          as.numeric(df$species)
        )$to(torch_long())
      },
      # 根据索引 i 返回一个单独的数据样本
      .getitem = function(i) {
        list(x = self$x[i, ], y = self$y[i])
      },
      # 返回特征数据 self$x 的行数,即数据集的样本总数
      .length = function() {
        dim(self$x)[1]
      }
    )
    
    # 张量赋值给 ds 函数
    ds <- penguins_dataset(penguins)
    # 查看张量的长度
    length(ds)
    # 查看第 1 行数据
    ds[1]
    
    展开/折叠结果
    [1] 333
    $x
    
    torch_tensor
       39.1000
       18.7000
      181.0000
     3750.0000
    [ CPUFloatType{4} ]
    
    $y
    torch_tensor
    1
    [ CPULongType{} ]
    
    
    # 创建随机由三个随机张量10个组成的数据集
    three <- tensor_dataset(
      # 从正态分布中生成随机数,张量的维数是10
      # 即包含10个元素的1维向量
      torch_randn(10), torch_randn(10), torch_randn(10)
    )
    # 从数据集中获取第一个样本
    three[1]
    
    展开/折叠结果
    [[1]]
    torch_tensor
     1.3905
    [ CPUFloatType{1} ]
    
    [[2]]
    torch_tensor
     2.1180
    [ CPUFloatType{1} ]
    
    [[3]]
    torch_tensor
    -0.3222
    [ CPUFloatType{1} ]
    
    # 去除带有 NA 的行
    penguins <- na.omit(penguins)
    # 构建函数,3:6 为矩阵张量;
    ds <- tensor_dataset(
      torch_tensor(as.matrix(penguins[, 3:6])),
      torch_tensor(
        # species转化为数值型再转化为长整数型再转化为张量
        as.numeric(penguins$species)
      )$to(torch_long())
    )
    # 取数据集中第一条数据,两个部分:
    # (1)特征张量(相当于x)
    # (2)标签(相当于y)
    ds[1]
    
    展开/折叠结果
    [[1]]
    torch_tensor
       39.1000    18.7000   181.0000  3750.0000
    [ CPUFloatType{1,4} ]
    
    [[2]]
    torch_tensor
     1
    [ CPULongType{1} ]
    
  • R语言卷积神经网络模型示例

    library(torch)
    
    convnet <- nn_module(
      "convnet",
      
      initialize = function() {
        
        # nn_conv2d(in_channels, out_channels, kernel_size)
        self$conv1 <- nn_conv2d(1, 16, 3)
        self$conv2 <- nn_conv2d(16, 32, 3)
        self$conv3 <- nn_conv2d(32, 64, 3)
        
        self$output <- nn_linear(2304, 3)
    
      },
      
      forward = function(x) {
        
        x %>% 
          self$conv1() %>% 
          nnf_relu() %>%
          nnf_max_pool2d(2) %>%
          self$conv2() %>% 
          nnf_relu() %>%
          nnf_max_pool2d(2) %>%
          self$conv3() %>% 
          nnf_relu() %>%
          nnf_max_pool2d(2) %>%
          torch_flatten(start_dim = 2) %>%
          self$output()
          
      }
    )
    
    model <- convnet()
    

    简要解析如下:

    1. 导入库library(torch)用于加载 torch 库,这是 R 的一个深度学习框架。
    2. 定义模型结构
      • 使用nn_module定义一个新的模块类convnet
      • 初始化函数initialize中:
        • nn_conv2d(1, 16, 3):定义了一个二维卷积层,输入通道数为1,输出通道数为16,卷积核大小为3×3。
        • nn_conv2d(16, 32, 3)nn_conv2d(32, 64, 3):后续的卷积层,分别从16通道转换到32通道,再到64通道。
        • nn_linear(2304, 3):定义一个全连接层,输入大小2304,输出大小为3。
    3. 前向传播函数forward
      • 数据流动通过各层,依次经过卷积、ReLU激活、最大池化(nnf_max_pool2d(2),池化窗口大小为2)。
      • 在经过三次卷积-激活-池化之后,将输出展平成一维(torch_flatten(start_dim = 2)),再通过全连接层生成最终输出。
    4. 模型实例化model <- convnet()创建了一个新的convnet模型实例。

    这个卷积神经网络主要用于处理二维图像输入,并通过特征提取和降维,最终输出一个具有3个类别的预测结果。

  • torch和luz在dataloader、张量和R对象的训练

    通过测试,dataloader的速度最快。张量和R对象的速度一样。

    library(torch)
    library(luz)
    
    # input dimensionality (number of input features)
    d_in <- 3
    # number of observations in training set
    n <- 1000
    
    # 生成一个1000x3的矩阵,其元素为从正态分布生成的随机数
    x <- torch_randn(n, d_in)
    # 定义线性关系的系数
    coefs <- c(0.2, -1.3, -0.5)
    # 计算目标变量y,使其成为输入x的线性组合,并添加噪声
    y <- x$matmul(coefs)$unsqueeze(2) + torch_randn(n, 1)
    # 使用输入和目标张量创建一个数据集对象
    ds <- tensor_dataset(x, y)
    # 构建一个数据加载器,批量大小为100,并启用随机洗牌以随机化数据顺序
    dl <- dataloader(ds, batch_size = 100, shuffle = TRUE)
    # 将隐藏层的神经元数量设置为32
    # dimensionality of hidden layer
    d_hidden <- 32
    # 将输出特征或预测的数量设为1
    # output dimensionality (number of predicted features)
    d_out <- 1
    
    # 使用torch包初始化一个神经网络模块
    net <- nn_module(
        # 接收输入维度、隐藏层维度和输出维度作为参数
      initialize = function(d_in, d_hidden, d_out) {
        # 构建一个由三个部分组成的序列化神经网络
        self$net <- nn_sequential(
            # 从输入层到隐藏层的线性变换
          nn_linear(d_in, d_hidden),
        #   对隐藏层输出应用ReLU激活函数
          nn_relu(),
        #   从隐藏层到输出层的线性变换
          nn_linear(d_hidden, d_out)
        )
      },
    #   定义网络的前向传递,将initialize中定义的序列模型应用于输入x
      forward = function(x) {
        self$net(x)
      }
    )
    
    # 初始化模型以进行训练
    fitted <- net %>%
    # 设置损失函数为均方误差(MSE),指定Adam优化算法
      setup(loss = nn_mse_loss(), optimizer = optim_adam) %>%
    #   配置模型的超参数
      set_hparams(
        d_in = d_in,   # 设置输入维度
        d_hidden = d_hidden,   # 设置隐藏层的神经元数量
        d_out = d_out   # 设置输出维度
      ) %>%
       # 使用提供的数据加载器dl训练模型
    #    dl: 包含训练数据集的数据加载器
    # 指定训练过程运行200个周期,即将整个数据集迭代200次
      fit(dl, epochs = 200)  
    
    # 替换dl为张量
    fitted <- net %>%
      setup(loss = nn_mse_loss(), optimizer = optim_adam) %>%
      set_hparams(
        d_in = d_in,
        d_hidden = d_hidden, d_out = d_out
      ) %>%
      fit(list(x, y), epochs = 200)
    
    # 替换dl为R对象
    fitted <- net %>%
      setup(loss = nn_mse_loss(), optimizer = optim_adam) %>%
      set_hparams(
        d_in = d_in,
        d_hidden = d_hidden, d_out = d_out
      ) %>%
      fit(list(as.matrix(x), as.matrix(y)), epochs = 200)
    
    
  • 模块化神经网络

    library(torch)
    # input dimensionality (number of input features)
    # 输入维度(特征的数量)被设定为3,每个输入数据点有3个特征
    d_in <- 3
    # number of observations in training set
    # 训练集中的观测数量被设定为100
    n <- 100
    # 创建一个100行3列的矩阵x
    x <- torch_randn(n, d_in)
    # 定义了一个包含系数的向量coefs
    coefs <- c(0.2, -1.3, -0.5)
    # 进行矩阵乘法运算,将矩阵x与系数coefs相乘
    # 并对每个元素添加噪声(通过unsqueeze添加一个额外的维度)
    # 最终生成目标变量y。
    y <- x$matmul(coefs)$unsqueeze(2) + torch_randn(n, 1)
    # 隐藏层32个维度
    d_hidden <-32
    # 输出层维度为1
    d_out <- 1
    # 创建序列模型
    net <- nn_sequential(
      nn_linear(d_in, d_hidden),   # 全连接层,线性层
      nn_relu(),   # 激活函数,引入非线性层
      nn_linear(d_hidden, d_out)   # 线性层,从隐藏层输出
    )
    # 初始化Adam优化器
    opt <- optim_adam(net$parameters)
    ### training loop --------------------------------------
    
    for (t in 1:200) {
      
      ### -------- Forward pass --------
      # 向前传递,通过net生成预测值
      y_pred <- net(x)
      
      ### -------- Compute loss -------- 
      # 使用均方误差(MSE)计算预测值y_pred与实际值y之间的损失
      loss <- nnf_mse_loss(y_pred, y)
      # 每10个周期输出一次损失值
      if (t %% 10 == 0)
        cat("Epoch: ", t, "   Loss: ", loss$item(), "\n")
      
      ### -------- Backpropagation --------
      # 在反向传播之前重置梯度为零
      opt$zero_grad()
      # 使用反向传播计算损失相对于网络参数的梯度
      loss$backward()
      
      ### -------- Update weights -------- 
      # 根据计算出的梯度更新网络的权重,以减少下一次迭代中的损失
      opt$step()
    
    }
    
    展开/折叠结果
    Epoch:  10    Loss:  3.248455 
    Epoch:  20    Loss:  3.051522
    Epoch:  30    Loss:  2.866707 
    Epoch:  40    Loss:  2.689961 
    Epoch:  50    Loss:  2.51879
    Epoch:  60    Loss:  2.350682 
    Epoch:  70    Loss:  2.18356 
    Epoch:  80    Loss:  2.018582 
    Epoch:  90    Loss:  1.856642 
    Epoch:  100    Loss:  1.700728
    Epoch:  110    Loss:  1.553768 
    Epoch:  120    Loss:  1.417934 
    Epoch:  130    Loss:  1.294667 
    Epoch:  140    Loss:  1.187055 
    Epoch:  150    Loss:  1.096451
    Epoch:  160    Loss:  1.022662 
    Epoch:  170    Loss:  0.9643999 
    Epoch:  180    Loss:  0.9189036 
    Epoch:  190    Loss:  0.8844466 
    Epoch:  200    Loss:  0.8586743