第二周:李宏毅机器学习笔记

第二周学习周报

  • 摘要
  • Abstract
  • 一、深度学习
    • 1.Backpropagation(反向传播)
      • 1.1 链式法则
      • 1.2 Forward pass(前向传播)
      • 1.3 Backward pass(向后传播)
      • 1.4 总结
    • 2. Regression(神奇宝贝案例)
      • 2.1 第一步:设置Model(A set of function)
      • 2.2 第二步:评估函数的好坏(goodness of function)
      • 2.3 第三步:找到最好的function(best function)
        • 2.3.1 Gradient Descent
          • 2.3.1.1 Gradient Descent的最小值问题(linear regression没有local optimal)
      • 2.4 结果以及优化
        • 2.4.1 过拟合现象(overfitting)
      • 2.6 改善模型
        • 2.6.1 重新设置模型(Redesign the model)
        • 2.6.2 正则化(Regularization)
  • 二、Pytorch学习
    • 1. Pytorch加载数据的初认知
      • 1.1 Dataset与Dataloader
      • 1.2 Dataset代码实战
  • 总结

摘要

这周主要对Deep Learning进行了进一步的学习,内容包括反向传播算法的过程原理。还学习了regression,根据宝可梦的案例学习到了Loss中使用正则化的技巧。此还继续学习了Pytorch课程,包括学习Dataset和Dataloader各自的功能,以及Dataset的代码实战。

Abstract

This week, I mainly conducted further learning on Deep Learning, including the process principle of backpropagation algorithm. I also learned about regression and learned the technique of using regularization in Loss based on the case of Pok é mon. I also continued to study Python courses, including learning the functions of Dataset and Dataloader, as well as practical coding for Dataset.

一、深度学习

1.Backpropagation(反向传播)

回顾一下梯度下降的过程:
在这里插入图片描述
在学习梯度下降的算法中,我们计算的过程中的θ这个vector(向量)是非常长的,即可能会有上百万个参数,为了有效率地计算面对这么多参数,我们就需要使用反向传播算法去完成θ的计算了。

在这里插入图片描述

1.1 链式法则

链式法则是在学习高等数学中求复合函数导数非常常用的一种方法。完成链式求导主要需要掌握两个步骤:
1、列出各个变量之间的关系
2、根据关系写出链式(同一条路径相乘、不同路径相加)
例子如下:
在这里插入图片描述
掌握了链式法则后,我们就要用来解决实际的问题了。
假设我们神经网络结构如下图所示,
其中Cn是yn与ŷn的交叉熵(可以理解为它们之间的距离,距离越近则误差越小
我们要求Cn对w(权重未知量)的偏导。
在这里插入图片描述

1.2 Forward pass(前向传播)

因为我们的C是经过整个神经网络得出结果后得出预测值y与真实值ŷ计算出来的,所以是一个整体的性的值,要求偏导,就要一层一层的计算
所以,我们把下图的下三角先提出来,先处理这个部分的计算从而以小见大,理解整个个过程的计算。
在这里插入图片描述
在这个上三角中,我们有::
feature :x1与x2
未知量:w1,w2,b
z:是他们计算结果。
在这里插入图片描述
那么我们如何用这些变量来表示C对w的偏导呢?
先拿w1举例:
在这里插入图片描述
在上述计算总结中,我们很明显可以发现一个规律,就是w(权重)对应的偏导,就是其对应输入的值。
比如,下图中,w = 1对应的偏导为 -1(输入值)、w = -1 对应的偏导值为0.12(输入值)…以此类推。
在这里插入图片描述

1.3 Backward pass(向后传播)

那么处理完z对w的偏导,还有一个令人头痛的C对z的偏导要计算,因为我们如果用z的变量表达C,就要一直推导,非常麻烦,因为z后面还有N多层。那么要如何解决呢?

假设我们再往下走一层,就有了以下参数:
a:z经过sigmoid运算后的结果。
w3、w4…:未知数
z’‘,z’':同z一个意思。
在这里插入图片描述
表示如下:
在这里插入图片描述
假设1:其下一层就是输出层。
在这里插入图片描述
计算方式如下:
在这里插入图片描述
假设其下一层不是输出层,就要找其下一层再推导,直到找到输出层为止
所以,一开始从输出层往前推导快一点,因为都是已知结果
在这里插入图片描述

1.4 总结

计算z对w偏导用forward pass,计算C对z的偏导用Backward pass
在这里插入图片描述

2. Regression(神奇宝贝案例)

在学习regression中,我们了解到其实一个回归问题,用于解决预测问题。
比如输入对应的函数,就会输出一个结果。
如下图所示,可以用于股市趋势的预测、自动驾驶的场景、网络购物推介等
在这里插入图片描述
下面我们用预测宝可梦的战斗力的例子,来更加深入的了解Regression。
我们输入函数的参数如下:
Xcp:是feature,表示宝可梦原先的战斗力。
Xs:是宝可梦的名字。
Xhp:是宝可梦的血量
Xw:宝可梦的重量
Xh:宝可梦的高度
在这里插入图片描述

2.1 第一步:设置Model(A set of function)

假设我们设置一组函数(可以有无数个),这些函数都是线性的(linear model),但是不一定是正确的,需要使用training date来验证哪个函数最合理,最后用来预测宝可梦进化后的战斗力。
在这里插入图片描述

2.2 第二步:评估函数的好坏(goodness of function)

我们根据进化后的真实值与初始值一一对应起来,并做成一幅直观的图。
这些数据称之为training date
横轴代表初始战斗力(x1…x10)
纵轴代表精华后的真实战斗力(ŷ1…ŷ10)
在这里插入图片描述
要评估模型的好坏,就要用到Loss function,这里我们采用平方差的方式来表示Loss的大小,其实Loss function就是用来输出这个模型到底有多差(所以L越小越好)
在这里插入图片描述
关于括号里面数字的由来:
在这里插入图片描述
在下面的图像中,图像的颜色代表L的大小,越红代表数值越大,越偏蓝色代表数值越小
在这里插入图片描述

2.3 第三步:找到最好的function(best function)

找到最佳的function,就要找到w与b使L 最小(min)
在这里插入图片描述

2.3.1 Gradient Descent

为了找到最小值,我们还是使用 Gradient Descent,接下来我们复习一下:
假设只有一个未知数w
其中包含local optimal(是我们随机取点,一直找到的最小值)和global optimal(全局最小值,基本上很难实现)
在这里插入图片描述
假设有两个未知数w和b,我们可以以此类推:
我们就可以先带入w0,b0,求偏导值,然后算出w1,b1,再代入w1,b1求出w2,b2.以此类推。
这时候的L的梯度就是一个二维的Vector
再多的参数就再加维度即可。
在这里插入图片描述
于是我们把,偏导完整的格式写出来,如下图所示:
在这里插入图片描述
用图像来表示上述过程,如下图:在这里插入图片描述

2.3.1.1 Gradient Descent的最小值问题(linear regression没有local optimal)

当我们使用gradient decent时候,会出现一个问题:
比如在下图的左图中,如果我们随机取不同的点,L最小值也会不一样
完全看我们的人品
但是!
线性回归不会出现这个问题,
因为其Loss function是convex(凸面的),无论我们从哪一点出发,都可以找到同一个最小值。
在这里插入图片描述

2.4 结果以及优化

经过计算,我们得到了最佳的w与b
运用这套线性的模型,我们最终得出一个结果:
在测试集上的L为35.0,在训练集上为31.9.
在这里插入图片描述
那么我们是否有办法让其L更低,让模型更加准确呢?

2.4.1 过拟合现象(overfitting)

于是我们可以增加未知量,让模型变得更加复杂,模型也就更加的精准。
我们先添加一个w2的未知数到方程中,看到结果在测试集和训练集中的Loss都减少了,
测试集的平均错误:从35.0->18.4
训练集的平均错误:从31.9->15.4
在这里插入图片描述
于是我们继续增加w3,w4,w5,持续增加模型的复杂度,如下图所示:
在这里插入图片描述
按照理论来说,我们模型的复杂度越高,在训练集中的错误就越低(前提是使用gradient descent找到最佳的未知数值)。
在这里插入图片描述
但是从这个表格中,我们就发现一个问题:
随着模型越来越复杂,我们的Training的average Error使越来越低,但是我们在Testing上的Error却在w4后越来越高,特别是加入w5后达到了惊人的232.1。
这种现象就称之为过拟合现象(overfitting),通常是由于模型过于复杂导致的
因为我们最重要的还是要预测数据,所以testing上的Error是非常重要的(要做大考型选手,不做模拟哥)
因此,我们最佳的模型实际上就是加入w3后的模型。
在这里插入图片描述

2.6 改善模型

我们上面设置的模型,只考虑了个别的情况,但是我们的宝可梦进化实际上是受很多条件影响的,例如:不同物种之间进化后的强度是不一样的。
因此我们要考虑上一些隐藏的因素,再重新设置模型
在这里插入图片描述

2.6.1 重新设置模型(Redesign the model)

我们可以设置这样一个Model:使用一个类似编程语言中的if语句来完成不同物种进化使用不同model的功能
如下图中所示:
在这里插入图片描述
当我要预测Pidgey的进化后的攻击力,其他物种的Xs都为0,只有Xs=Pidgey的Xs为1
在这里插入图片描述
经过这一改变后,
我们的Training Data的Average error为3.8
Tesing Data的Average error 为14.3.
很明显这种对症下药的model效果非常显著
在这里插入图片描述
再或者我们在这个基础上,让模型更加复杂一点我们再增加一些未知数,模型说不定会预测地更加的精准
在这里插入图片描述

2.6.2 正则化(Regularization)

正则化是一种防止模型过拟合的手段,通过给损失函数加上一些限制条件,使模型参数更接近于0。
我们在Loss function中可以加入一个λ∑(wi)²,来使得线段更加平滑。

为什么要变得平滑呢?
因为越平滑的线就越能够减少外界的干扰,预测的准确度就越高(比如我们的输入数据有受到了一些干扰,会影响结果,我们加入这个部分后,就能减少这些干扰对结果的影响
在这里插入图片描述
我们通过控制λ的大小来控制线的平滑程度,我们需要平滑,但不能过于平滑。
因为可以看到当我们的λ从0增加到100,其在训练集和测试集上的Error都再一直下降
但是100后,图像就有一个转折点,再增加Error就变大了。
因此我们要根据测试结果,选定一个最佳λ,使得我们的效果最佳。
在这里插入图片描述

二、Pytorch学习

1. Pytorch加载数据的初认知

1.1 Dataset与Dataloader

在Pytorch中如何读取数据主要分为两个类,一个是Dataset、一个是Dataloader。

假设数据就是一堆垃圾,我们要在这堆垃圾中寻找我们有用的数据。
就要使用Dataset完成,然后经过Dataloader打包后,再传入网路中,如下图所示:
在这里插入图片描述
其中Dataset与Dataloader的功能如下:

名称DatasetDataloader
功能提供一种方式去获取数据以及其label (获取每一种数据以及其label、并告诉我们共有多少数据)为后面的网络提供不同的数据形式

1.2 Dataset代码实战

接下来,我们下载一个数据集,来学习Dataset
数据集下载链接https://download.pytorch.org/tutorial/hymenoptera_data.zip
解压打开后可以看到这个数据集包括训练集和验证集,里面都是一些蚂蚁和蜜蜂的图片,如下图所示:
在这里插入图片描述
这里的label 就是文件夹对应的名称(这是众多的组织形式之一)
在这里插入图片描述
在这里插入图片描述
接下来,我们启动jupyter notebook,输入以下代码,引入Dataset类

from torch.utils.data import Dataset

然后我们可以使用help函数,查看使用方法

help(Dataset)

在这里插入图片描述
或者使用**Dataset??**查看更加直观的使用方法

Dataset??

在这里插入图片描述
从上述英文,我们大致了解到Dataset的作用就是用来提取数据的
在这里插入图片描述
图片作为输入,一般是将图片的路径
在这里插入图片描述
接下来我们把数据集放到项目里(目的是为了生产相对路径,好说明图片位置):在这里插入图片描述
我们在python console中输入代码,将图片的绝对路径传输进去

from PIL import Image //导入PIL用于导入图片
img_path = "E:\DeepLearing\learn_pytorch\\Dataset\\train\\ants\\0013035.jpg" //图片绝对路径
img = Image.open(img_path) //赋值给img
img.size //查看图片的尺寸
img.show() //展示图片

效果如下:
在这里插入图片描述

import os
dir_path = "Dataset/train/ants"
img_path_list = os.listdir(dir_path)

在这里插入图片描述

然后,如果我们想要获取图片的所有地址,就需要用list获取图片文件夹,然后再用getitem获取的idx获取每张图片的地址。
在pycharm上输入如下代码:
(//后面为注释)

from torch.utils.data import Dataset //引入Dataset类
from PIL import Image //用于导入图片
import os //用于导入图片路径


class MyData(Dataset):

    def __init__(self, root_dir, label_dir): //初始化。self用于该类的全局变量,用于后面两个函数的作为变量使用
        self.root_dir = root_dir //根路径 比如:"Dataset/train"
        self.label_dir = label_dir //标签名,比如"ants""bees"
        self.path = os.path.join(self.root_dir, self.label_dir)//拼接在一起
        self.img_path = os.listdir(self.path) //转化为字节流

    def __getitem__(self, idx): //该函数用于获取各图片
        img_name = self.img_path[idx] //idx,表示每张图片序号,例如:idx = 0表示第一张图
        img_item_path = os.path.join(self.root_dir, self.label_dir, img_name) //拼接在一起
        img = Image.open(img_item_path) //赋值图片路径
        label = self.label_dir //赋值标签名字
        return img, label //返回图片信息和标签名

    def __len__(self): //用于返回有多少张图
        return len(self.img_path) //返回图片长度

//类实例化
root_dir = "Dataset/train" //训练集根路径
ants_label_dir = "ants" //蚂蚁标签
bees_label_dir = "bees" //蜜蜂标签
ants_dataset = MyData(root_dir, ants_label_dir) //创建蚂蚁dataset实例
bees_dataset = MyData(root_dir, bees_label_dir)//创建蜜蜂dataset实例
train_dataset = ants_dataset + bees_dataset //创建蚂蚁和蜜蜂dataset实例

输入后便创建了实例
在这里插入图片描述
运行如下代码,展示蚂蚁训练集第一张图片:

img,label = ants_dataset[0]
img.show()

在这里插入图片描述
运行如下代码,展示蜜蜂训练集第一张图片:

img,label = bees_dataset[0]
img.show()

在这里插入图片描述

len(bees_dataset)//蜜蜂训练集图片数量
len(ants_dataset)//蚂蚁训练集图片数量
len(train_dataset)//总训练集数量(蜜蜂 + 蚂蚁)

在这里插入图片描述

接下来,我们输入如下代码,创建image对应的label文件
首先我们要在Dataset目录下创建一个ants_label与bees_label用来存放txt的label文件。
代码如下:

import os

root_dir = "Dataset/train"
target_dir = "ants_image"
img_path = os.listdir(os.path.join(root_dir, target_dir))
label = target_dir.split('_')[0]
out_dir = "ants_label"
for i in img_path:
    file_name = i.split('.jpg')[0]
    with open(os.path.join(root_dir, out_dir, "{}.txt".format(file_name)), 'w') as f:
        f.write(label)

这段代码的作用是将指定目录下的所有以".jpg"结尾的图片文件的标签写入同名的".txt"文件中。假设有一个名叫"antsimage"的目录,里面存放了一些以"ants"开头的蚂蚁图片,我们需要将其标签写入同名的".txt"文件中,以便后续使用。

代码核心部分使用了Python的os模块来定位文件位置和创建文件
主要分为以下步骤:
1. 定义根目录rootdir、目标目录targetdir和标签label。在该段代码中,rootdir指的是存放所有图片的目录;targetdir指的是存放待处理图片的目录名称,本例中为"ants_image";而label则是标签,这里为"ants"。
2. 获取目标文件夹下所有图片文件的名称,并去掉文件扩展名".jpg",只保留文件名。
3. 遍历所有文件,使用with open()语句创建同名".txt"文件,并向其中写入标签label。
4. 循环结束后,所有的图片的标签都写入了同名".txt"文件中,存放在指定的目录out_dir下。

总之,这段代码的作用是将一些图片的标签写入同名文件中,方便后续使用。
在这里插入图片描述
将上述代码的ants换成bees就可以生成蜜蜂的label文件
在这里插入图片描述

总结

这一周在Deep Learning的课程李宏毅中学习到了反向传播算法、regression宝可梦案例,其中在反向传播算法主要是为了提高了在梯度下降算法中的计算效率,在反向传播算法中分为foward pass和 backward pass两种模式,都是解决了在链式求导的裂项中如何求值的问题。在regression中复习了之前的内容,并学习率正则化(Regularization)这个知识点,主要用于防止过拟合,使Loss变得平滑,减少干扰。此外还继续学习了pytorch,学会了如何使用Dataset和定义其里面的getitem(用于获取图片)和len(用于统计图片数量)函数,并用文件操作完成label文件的批量创建。
最后希望继续保持学习的热情,更多的去了解底层原理,下一周计划学习classification的神奇宝贝案例、逻辑回归,以及继续学习pytorch的TensorBoard的使用课程。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Bug记录:【com.fasterxml.jackson.databind.exc.InvalidDefinitionException】

bug记录 序列化错误 异常com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 完整错误(主要是FAIL_ON_EMPTY_BEANS) 00:15:20.250 [http-nio-3000-exec-1] ERROR org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet] - S…

【漏洞复现】TerraMaster TOS exportUser.php 远程命令执行

免责声明: 本文内容旨在提供有关特定漏洞或安全漏洞的信息,以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步,并非出于任何恶意目的。阅读者应该明白,在利用本文提到的漏洞信息或进行相关测…

Windows编程[下]

Windows编程[下] 一、线程1. 内核对象2.多线程群聊服务器3.多线程群聊客户端4.线程同步之事件对象常用函数和参数解释 二、进程三、Qt1.第一个Qt项目2.Qt助手的使用3.QPushButton简介4.Qt对象树对象树的基本概念使用对象树模式的好处对象树的问题 5.信号与槽5.1 自定义信号和槽…

通用的职位招聘小程序ui模板

蓝色简单的校园招聘,行业招聘,职位招聘手机小程序页面模板。包含:职位列表、职位详情、基本信息填写、登录、个人主页、消息页面等功能 通用的职位招聘小程序ui模板

InvalidVersionSpecError: Invalid version spec: =2.7解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

驾校管理系统的全面革新与升级

智慧驾校系统是一款专为现代驾校量身定制的综合性管理平台,它深度融合了云计算、大数据、物联网及人工智能等前沿技术,旨在为驾校打造一个高效、智能、便捷的运营生态系统。该系统通过数字化、信息化的手段,彻底革新了传统驾校的管理模式,不仅极大地提升了驾校的运营效率,…

初识Spark

一、简介 官网:Apache Spark™ - Unified Engine for large-scale data analytics Apache的顶级项目,用于大规模数据处理的统一分析引擎。 支持语言:Java、Scala、Python和R (源码为Scala) 高级工具: 1、SparkSQL用于SQL和结构…

ARM汇编与机器码、汇编指令

文章目录 1. CISC与RISC指令集 2. ARM汇编指令 3. 汇编与机器码 4. 汇编指令格式 5. MOV指令 6. BL指令 7. B指令 8. ADD/SUB指令 9. LDR/STR指令 1. CISC与RISC指令集 根据指令的复杂度,所有CPU可以分为两类: CISC(Complex Instr…

破局 AI 2.0 时代:利用 AI 提升自我核心竞争力

文章目录 破局 AI 2.0 时代:利用 AI 提升自我核心竞争力1. AI 2.0 时代1.1 特点1.2 发展1.3 影响 2. AI 2.0 时代的机遇 & 挑战2.1 AI 对行业市场的冲击2.2 挑战变为机遇2.3 不同场景下的 AI 效能提升2.3.1 自动化办公任务2.3.2 提升学习效率2.3.3 创意生成与内…

SpringBoot彩蛋之定制启动画面

写在前面 在日常开发中,我们经常会看到各种各样的启动画面。例如以下几种 ① spring项目启动画面 ② mybatisplus启动画面 ③若依项目启动画面 还有很多各式各样好看的启动画面,那么怎么定制这些启动画面呢? 一、小试牛刀 ① 新建一个Spr…

【分布式系统三】监控平台Zabbix对接grafana(截图详细版)

目录 一.安装grafana并启动 二.浏览器访问 三.导入zabbix数据,对接grafana 四.如何导入模版 以前两篇博客为基础 【分布式系统】监控平台Zabbix介绍与部署(命令截图版)-CSDN博客 【分布式系统】监控平台Zabbix自定义模版配置-CSDN博客 …

前端面试题(CSS篇五)

一、设备像素、css 像素、设备独立像素、dpr、ppi 之间的区别? 设备像素指的是物理像素,一般手机的分辨率指的就是设备像素,一个设备的设备像素是不可变的。 css像素和设备独立像素是等价的,不管在何种分辨率的设备上,…

网络连接线相关问题

问题1; 直通线为什么两头都是T568B?是否可以两台T5568A?或者任意线序,只需两头一致? 不行,施工规范规定。(原因;网线最长距离100m,实际用起来要把网线包管,走…

Kafka第四篇——生产数据总体概括,源码解析分区策略,数据收集器,Sender发送线程,key值

目录 流程图以及总体概述 拦截器 分区器以及分区计算策略 为啥进行分区计算? producer生产者怎么知道有哪些分区? 分区计算 如何自定义实现分区器? 想说的在图里啦!宝宝!💡 ​编辑 如果key值忘记传递了呢&a…

前端后花园周刊vol.18-React Native 称唯一推荐的社区框架是Expo

⚡️行业动态 React Native 团队推荐使用 Expo 框架构建应用程序 React Native 发文称:唯一推荐的社区框架是Expo,Expo 的开发者从 React Native 早期就开始支持 React Native 生态系统,相信 Expo 提供的开发者体验是同类中最好的。 &…

vscode调试教程

VSCode调试 VSCode Debuggers VSCode使用launch.json进行细粒度的控制,可以启动程序或将其附加到复杂的调试场景中 打开Run and Debug视图Ctrl Shift D 点击create a launch.json file,选择C(GDB/LLDB) 会在工作目录自动创建.vscode/launch.json文…

简单的基追踪一维信号降噪方法(MATLAB 2018)

基追踪法是基于冗余过完备字典下的一种信号稀疏表示方法。该方法具有可提高信号的稀疏性、实现阈值降噪和提高时频分辨率等优点。基追踪法采用表示系数的范数作为信号来度量稀疏性,通过最小化l型范数将信号稀疏表示问题定义为一类有约束的极值问题,进而转…

【linux服务器】大语言模型实战教程:LLMS大模型部署到个人服务器或嵌入式开发板(保姆级教学)

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 引言 说到大语言模型相信大家都不会陌生,大型语言模型(LLMs)是人工智能文本处理的主要类型,也现在最流行的人工智能…

julia系列17: tsp问题代码整理

1. 常用库和基础函数 这里是优化版的函数: using TSPLIB,LKH,Distances,PyPlot MaxNum 10000 tspreadTSPLIB(:att48) dist [round.(Int,euclidean(tsp.nodes[i,:],tsp.nodes[j,:])) for i in 1:tsp.dimension,j in 1:tsp.dimension]; pos(tsp::TSP,t::Vector{In…

Games101学习笔记 Lecture17 Materials and Appearances

Lecture17 Materials and Appearances 材质 BRDF一、Diffuse/Lambertian Material二、Glossy Material三、Ideal reflective/ refractive Material (BSDF)1.镜面反射2.镜面折射3.菲涅尔项 Fresnel 四、Microfacet BRDF 微表面五、Isotropic / Anisotropic Materials (BRDFs)An…