矩阵乘法用%*%符号。矩阵乘法的A%*%B和B%*%A结果是不同的,没有交换律。
A <- matrix(1:4,nrow=2 ,byrow=T)
B <- matrix(5:8,nrow=2 ,byrow=T)
A %*% B
矩阵乘法用%*%符号。矩阵乘法的A%*%B和B%*%A结果是不同的,没有交换律。
A <- matrix(1:4,nrow=2 ,byrow=T)
B <- matrix(5:8,nrow=2 ,byrow=T)
A %*% B
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)

sigmoid函数是平滑的阶跃函数。
sigmoid <- function(x){
return(1/(1+exp(-x)))
}
x <- c(-1.0,1.0,2.0)
y <- sigmoid(x)
plot(x,y)

阶跃函数(Step Function)是一种在某些点上发生突变的函数,通常用于数学、工程和计算机科学中。最常见的阶跃函数是Heaviside阶跃函数,它在某个特定点(通常是0)发生变化。
x <- c(-1, 1, 2, 2, 0)
x
y <- x > 0
y
y <- as.integer(y)
y
plot(x,y)

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)
# 获取 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
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} ]
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()
简要解析如下:
library(torch)用于加载 torch 库,这是 R 的一个深度学习框架。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。forward:nnf_max_pool2d(2),池化窗口大小为2)。torch_flatten(start_dim = 2)),再通过全连接层生成最终输出。model <- convnet()创建了一个新的convnet模型实例。这个卷积神经网络主要用于处理二维图像输入,并通过特征提取和降维,最终输出一个具有3个类别的预测结果。
通过测试,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