3.2 线性回归的从零开始实现

1. 生成数据集

我们生成一个包含1000个样本的数据集, 每个样本包含从标准正态分布中采样的2个特征。 我们的合成数据集是一个矩阵

 函数synthetic_data()接收线性模型的w,b以及要生成的样本的数量为参数,创建样本的特征矩阵X以及标签向量y,分别返回:

 

torch.normal(0,1,(nums_examples,len(w)))生成均值为0,方差为1,形状为(nums_examples,len(w))的随机正太分布数据,作为样本的特征矩阵。注意这特征值和标签值都是随机生成的,这是没有任何现实意义的数据集,仅作为熟悉线性回归流程的工具。

注意:如果返回y的时候直接返回y,而不是返回y.reshape(-1,1),会出现这样的问题:X的维度是(nums_examples,len(w)),w的维度是(len(w)),matmul(X,w)下来维度是(nums_examples),而不是(nums_examples,1)。而我们想要的维度是(nums_examples,1)。注意,矩阵向量积虽然mv(X,w)和matmul(X,w)结果是一样的,它们在处理的过程中会将w的维度变成(len(w),1),与X进行计算,但算完了保存结果时,结果的维度是(nums_examples)的。

2. 读取数据集

我们定义一个函数data_iter(batch_size,features,labels),传入整个数据集的features,labels,以及我们每次要读取的batch_size的大小,使用yield让这个函数循环地返回每个batch_size的features以及labels:

首先,我们使用num_examples = len(features)获取整个数据集的样本的个数,然后,创建随机访问的索引indices,函数random.shuffle(indices)用于将列表indices中的数据随机打乱。yield关键词用于返回features[batch_indices]和labels[batch_indices]的值,并与下面的for循环联动,将这些值循环地传入X,y中。

 注意,这里边,在生成列表indices的时候,一定是使用list()将它强制转换成list类型,而不是用torch.tensor()将它强制转换成为tensor类型。因为在后面使用torch.tensor(indices[i:min(i+batch_size,num_examples)])来取出部分indices的元素时,如果前面使用的是torch.tensor()强转,则此时indices的每一个元素都是tensor,indices的类型也是tensor,再用torch.tensor()强转,就是把tensor强转为tensor;如果在前面就使用了torch.tensor()将indices转为tensor类型,后面就不用再强转了,以下代码也是可以的:

 

3. 初始化模型参数

注意到模型的参数为w和b。我们将w初始化为均值为0,方差为0.01的正态分布,将b初始化为0:

4. 定义模型

模型的定义是,给定我们输入特征X,以及参数w,b,用来输出样本标注y的函数:

 注意,上面的Xw是一个向量,而b是一个标量(Xw和b都是张量),计算Xw+b时,会采用广播机制,Xw的每一个值都会加上b。

 

5. 定义损失函数

 损失函数的定义是,传入真实值y和估计值y_hat,返回在定义的损失函数下的损失的过程。

这里面我们把y给reshape成了y_hat的形状,是为了保证万无一失。(在本例中不reshape也能正常运行)

 

6. 定义优化算法

优化算法是传入模型的全部参数、学习率以及 batch_size,各个参数根据自己的梯度优化自己的过程:

这里要加with torch.no_grad():,表示下面的过程不需要计算梯度,不加就会报错,暂时搞不清楚什么原因;

注意参数更新完之后,一定要把它们的梯度清零,以便下一个batch_size的训练。

这里对参数的传入其实是这样的:

 只不过我们可以把w,b作为一个列表传入进来,然后用for循环访问,代码更加简洁。

 

7. 训练

 我们首先定义学习率、batch_size、num_epochs,即要训练多少个epoch。

这里面[w,b]是一个list,它的两个元素都是torch.tensor类型的,w是一个有两个元素的tensor,b是一个标量tensor。

对于{float(train_l.mean()):f},用float是将它从tansor强制转换成float型,冒号f,即":f"的意思是要将这个float型变量用六位小数输出。

可以看到,我们每次取出来一个batch_size,都是可以对全局所有的参数进行更新的。

 

完整代码如下:

 1 import torch
 2 import random
 3 from d2l import torch as d2l
 4 
 5 #生成人造数据集
 6 def synthetic_data(w,b,num_examples):
 7     X = torch.normal(0,1,size=(num_examples,len(w)))
 8     y = torch.matmul(X,w) + b
 9     y += torch.normal(0,0.01,y.shape)
10     return X,y.reshape(-1,1)
11 
12 #输入batch_size,特征,标签,按batch_size循环每次读取一批数据
13 def data_iter(batch_size,features,labels):
14     num_examples = len(features)
15     indices = list(range(num_examples))
16     random.shuffle(indices)
17     for i in range(0,num_examples,batch_size):
18         batch_indices = torch.tensor(indices[i:min(i+batch_size,num_examples)])
19         yield features[batch_indices], labels[batch_indices]
20         
21 def linreg(X,w,b):
22     y = torch.matmul(X,w) + b
23     return y;
24 
25 def squared_loss(y_hat,y):
26     loss = (y_hat-y.reshape(y_hat.shape))**2/2
27     return loss
28 
29 def sgd(params,lr,batch_size):
30     with torch.no_grad():
31         for param in params:
32             param -= param.grad * lr / batch_size
33             param.grad.zero_()
34             
35 #定义一些与训练有关的参数
36 epoch_nums = 3
37 batch_size = 10
38 lr = 0.03
39 net = linreg
40 loss = squared_loss
41 
42 #初始化模型参数
43 w = torch.normal(0,0.01,size=(2,1),requires_grad=True)
44 b = torch.zeros(1,requires_grad=True)
45 
46 #调用数据集生成函数生成数据集
47 true_w = torch.tensor([2,-3.4])
48 true_b = 4.2
49 num_examples = 1000
50 features,labels = synthetic_data(true_w,true_b,num_examples) ###111111111111###
51 
52 #训练
53 for epoch in range(epoch_nums):
54     for X,y in data_iter(batch_size,features,labels):
55         y_hat = net(X,w,b)
56         l = loss(y_hat,y)
57         l.sum().backward()
58         sgd([w,b],lr,batch_size)
59     with torch.no_grad():
60         train_loss = loss(net(features,w,b),labels)
61         print(f'epoch {epoch+1}, loss {float(train_loss.mean()):f}')

注意在#1处,曾经错误地将参数true_w,true_b传入成了w,b,导致报错:

Trying to backward through the graph a second time.........

 

本文转载于网络 如有侵权请联系删除

相关文章

  • innodb是如何存数据的?yyds

    hi,大家好,我是苏三,又跟大家见面了。前言 如果你使用过mysql数据库,对它的存储引擎:innodb,一定不会感到陌生。众所周知,在mysql5以前,默认的存储引擎是:myslam。但mysql5之后,默认的存储引擎已经变成了:innodb,它是我们建表的首选存储引擎。那么,问题来了:innodb底层是如何存储数据的?表中有哪些隐藏列?用户记录之间是如何关联起来的?如果你想知道上面三个问题的答案,那么,请继续往下面看。本文主要包含如下内容:1.磁盘or内存?1.1磁盘数据对系统来说是非常重要的东西,比如:用户的身份证、手机号、银行号、会员过期时间、积分等等。一旦丢失,会对用户造成很大的影响。那么问题来了,如何才能保证这些重要的数据不丢呢?答案:把数据存在磁盘上。当然有人会说,如果磁盘坏了怎么办?那就需要备份,或者做主从了。。。好了,打住,这不是今天的重点。言归正传。大家都知道,从磁盘上读写数据,至少需要两次IO请求才能完成。一次是读IO,另一次是写IO。而IO请求是比较耗时的操作,如果频繁的进行IO请求势必会影响数据库的性能。那么,如何才能解决数据库的性能问题呢?1.2内存把数据存

  • 交换分区的查看与扩容

    任务1Linux交换分区的功能和大小设置建议 功能:SWAP就是LINUX下的虚拟内存分区,它的作用是在物理内存使用完之后,将磁盘空间(也就是SWAP分区)虚拟成内存来使用.需要注意的是,虽然这个SWAP分区能够作为"虚拟"的内存,但它的速度比物理内存可是慢多了,也会降低磁盘速度大小: 在内存为8G以内,建议是内存的1.5-2倍任务2解读命令“free-m”的输出主要信息 加上-h可视阅读,以MB显示 信息解读 Mem:系统内存使用情况的全局描述 total:系统的物理内存总量,total=used+free used:已使用的物理内存,used=shared+buff+cached+(-/+buff/cache那栏的used) free:空闲的物理内存,即既没有被进程使用,也没有用作操作系统的buff和cached。 shared:共享内存用量,如存放共享库。 buffers:用于缓冲操作系统的目录文件,inode的值,如使用ls命令查看大目录时,这个值会增加 cached:用于操作系统页缓存,主要用于缓存已打开的文件。操作系统为了避免频繁的磁盘读写操作,会尽可能

  • Java - IO System类支持和缓冲流

    System类的支持和缓冲流System类对IO的支持在System类中,为了支持IO操作提供了三个常量:错误输出:publicstaticfinalPrintStreamerr;复制publicstaticfinalPrintStreamout;复制publicstaticfinalInputStreamin;复制错误输出System.err是PrintStream类对象,此对象专门负责进行错误信息的输出操作几乎无用!system.err和System.out的功能是完全一样的;之所以设计System.err主要目的就是err可以输出用户看不见的错误,而System.out输出用户可见的信息。信息输出System.out是在Java中专门支持屏幕输出信息的操作对象(对象由系统赋值实例化)publicclassTestDemo{ publicstaticvoidmain(String[]args)throwsIOException{ OutputStreamout=System.out; out.write("Hello,World!".getBytes(

  • linux下编译安装nginx完整版

    0x01Nginx有哪些优点更快这表现在两个方面:一方面,在正常情况下,单次请求会得到更快的响应;另一方在高峰期(如有数以万计的并发请求),Nginx可以比其他Web服务器更快地响应请高扩展性Nginx的设计极具扩展性,它完全是由多个不同功能、不同层次、不同类型且耦合度极 低的模块组成。因此,当对某一个模块修复Bug或进行升级时,可以专注于模块自身,无须 在意其他。高可靠性Nginx的高可靠性来自于其核心框架代码 的优秀设计、模块设计的简单性;官方提供的常用模块都非常稳定,每个worker进程 相对独立,master进程在1个worker进程出错时可以快速“拉起”新的worker子进程提供服务。低内存消耗一般情况下,10000个非活跃的HTTPKeep-Alive连接在Nginx中仅消耗2.5MB的内存,单机支持10万以上的并发连接理论上,Nginx支持的并发连接上限取决于内存,10万远未封顶。热部署master管理进程与worker工作进程的分离设计,使得Nginx能够提供热部署功能,即可以 在7×24小时不间断服务的前提下,升级Nginx的可执行文件。并且也支持不停止服务就 更新配

  • 晓说区块链 | 为何要用区块链技术实现智能合约?

    智能合约貌似就是一段脚本,可以被准确执行。这用传统的技术也能实现,为什么一定要用区块链技术呢?区块链又是否真的能应用于电商等现实交易?本期《晓说区块链》,陈晓东先生(维基链首席技术官)将围绕这些话题,为大家给出他的解读。网友:为什么要用区块链技术实现智能合约?智能合约貌似就是一段脚本,可以被准确执行。这用传统的技术也能实现,为什么一定要用区块链技术呢?个人的理解,区块链的特点有两个1.数据不能修改、删除,只能查看和增加。2.去中心化。避免了中心化的“人”因素。关于特点1,传统技术通过软件做限制,可以实现。特点2,信用好的机构做担保,保证特点1不会被修改。就是保证数据不被修改和删除(或者可以把数据公开,如果被修改了,大家都能发现)意思相当于:区块链=传统技术+机构信用担保。当然,在一些事情上,很难保证“人”不作恶。不过在大部分的事情上(或者说不大的事情上),“人”的信用还是值得相信的,毕竟日常很多事情都是基于“人”的信用进行的(比如,中小事情)。因此,在不大的事情上,是不是可以用:传统技术+机构信用担保,来实现区块链要做的事情呢?陈晓东:什么时候采用区块链,什么时候不采用区块链,其实可以

  • Flv文件格式解析

    Flv文件解析Flv文件分为header和body两个部分image.pngHeaderFlvheader.pngBodyTAGFlvTAG.pngTAG_DATAScrpitTAG_DATA_Scrpit.pngVideoTAG_DATA_Video_CONFIG.pngTAG_DATA_Video_NAUL.pngAudioTAG_DATA_Audio.png参考flv格式详解+实例剖析

  • 最具争议的12个数学事实

    来自:译言网 译者:沉香玉原文作者:WalterHickey 链接:http://select.yeeyan.org/view/102595/357495总有些出人意料的数学题,目的就是为了测试和提升人的智力极限。下面这12个简单的数学题,在学生中引起了巨大的争议,但却都是无可争辩的事实。 他们都具有悖论和概率的特性,而且总是能引起一些争论。如果你想通过数学的方法来打动朋友或迷惑敌人的话,那就往下看吧。

  • AI一分钟|快播王欣出狱,与姚劲波、何小鹏一起畅谈人工智能、区块链

    一分钟AI王欣出狱后首露面:与姚劲波、何小鹏等会面谈AI和区块链马斯克:特斯拉将开展跨美国无人驾驶坚决不用激光雷达“亿航184”首次飞行演示,“打飞的”上班成为可能,今年计划实现小批量交付阿里巴巴投资拍摄机器人与AI主题电影《钢铁战士》旷视科技Face++武汉成立人工智能工程院着重AI硬件创新研发腾讯与Medopad达成合作意向,研究AI的临床应用14岁女孩开发APP,用人工智能和面部识别技术帮奶奶想起自己交通运输部:中国正在编制无人驾驶技术规划,研究起草技术规范,并在建设测试基地开发光子芯片以提升AI计算能力,Lightmatter获1100万美元A轮融资边界智能融资数千万元.ai域名再成座上宾嘀!恭喜你,周四《AI一分钟》打卡成功! 没看够,以下两分钟看详细新闻1.王欣出狱后首露面:与姚劲波何小鹏等会面谈AI区块链2月7日晚间,小鹏汽车董事长何小鹏在微博发文表示,“今天特别高兴王欣兄弟的回归,身体很好,思维完全和大家一起,兴致勃勃的一起讨论了AI,视频,区块链等技术的发展,也听到了很多秘闻和往事,坚信不久将来,江湖中会有王大师的下一段的传奇故事。”并配了和姚劲波、王欣等在一起的

  • 精选国产 IntelliJ IDEA 优秀插件 | 码云周刊第 50 期

    IntelliJIDEA在业界被公认为最好的Java开发平台之一,在智能代码助手、代码自动提示、J2EE支持、Ant、JUnit、代码审查等方面都有不错的表现,且支持基于Android平台的程序开发。相信国内也有一些公司采用IntelliJIDA进行开发,这期周刊会给大家推荐6款国产IntelliJIDEA优秀插件,好的工匠需要用好的工具才能创造出优秀的艺术品。如果大家有好的IDEA插件项目,也可以托管到码云上,我们会及时给予推荐。最后,如果你很喜欢以下提到的项目,别忘了分享给其他人噢。码云项目推荐1.项目名称:码云IntelliJIDEA插件Intellij-Gitee项目简介:码云IntelliJIDEA插件由码云推出的Git插件,该插件基于IntelliJIDEAGithub插件开发,可实现IntelliJIDEA与开源中国码云平台对接,其主要功能如下:登录功能。输入码云帐号和密码可以直接登录到码云。获取用户项目列表。在登录码云之后,用户可以获取码云线上项目列表,并可选择该用户的任意项目进行clone。推送项目。在登录码云之后,用户可以将项目push到码云。创建项目。对于仅存在于

  • 内容协商 (Content Negotiation)

    大多数响应包含一个实体,此实体包含人类用户能理解的信息。通常,希望提供给用户相应于请求最容易得到的实体。对服务器和缓存来说,不幸的是,并不是所有的用户都对这个最容易得到的实体有喜好,并且并不是所有的用户代理(如web浏览器)都能一致的呈现这些实体。所以,HTTP提供了一些“内容协商”机制—当有多个可得的表现形式的时候,对特定的响应选择最好的表现形式的处理过程。注意:没有称做“格式协商”(译注:“格式”指的是“媒体类型”)的,因为可替换的表现形式可能会同原来的有相同的媒体类型,只是利用了此媒体类型不同的性质,例如一种不同的语言。任何包含一个实体主体的响应包括错误响应都可能会受协商的支配。有两种类型的内容协商在HTTP中:服务器驱动协商和代理驱动协商。这两种类型的协商具有正交性并且能被单独使用或联合使用。一个联合使用方法的协商会被叫做透明协商,当缓存利用代理驱动协商的信息的时候,此代理驱动协商的信息被为后续请求提供服务器驱动协商的源服务器提供。一、服务器驱动协商(Server-drivenNegotiation)如果响应的最好的表现形式的选择是通过服务器上的算法来实现,那么这种方式的协商称

  • window.navigator.userAgent用来区分设备和浏览器

    javascript的navigator对象 navigator为Window对象的一个属性,指向了一个包含浏览器相关信息的对象。navigatot中包含了一些常用到的属性,如    navigator.appVersion浏览器的版本号  navigator.appName浏览器的名称  navigator.language浏览器使用的语言  navigator.platform浏览器使用的平台  navigator.userAgent浏览器的user-agent信息   1//各主流浏览器版本判断 2functiongetExplorer(){ 3varexplorer=window.navigator.userAgent; 4//ie 5if(explorer.indexOf("MSIE")>=0){ 6return"IE"; 7} 8//firefox 9elseif(explorer.indexOf("Firefox")>=0){ 10return"Firefox"; 11} 12

  • Matlab中常用的画图语句

    1.imshow(A,[])与imshow(A)的区别: 主要是针对灰度图来说的,imshow(A)默认值范围是0~255 而当灰度图A的像素值变化在0~20时,直接使用imshow(A)可能输出全黑。而imshow(A,[])则取min(A(:))~max(A(:))归一化到0~1之间。   2.在图像中画矩形框。 rectangle('Position',[x,y,w,h],'LineWidth',4,'EdgeColor','b');(x,y是左上角的坐标,w/h为矩形框的宽高)复制 3.画出分割部分 seg=my_anno(1).segmentation [X,Y]=meshgrid(1:w,1:h);  %点[X(i),Y(i)]是对图上所有点的遍历 mask=inpolygon(X,Y,seg(1:2:end),seg(2:2:end)); mask_all=or(maks,mask_all);%%同一张图中有多个物体seg信息融合复制 具体inpolygon函数使用可以参开:https://jingyan.baidu.com/article/597035

  • epoch

    每学一遍数据集,就称为一个epoch,要在每个epoch都要打乱数据的顺序。

  • VISIO中的工具栏、菜单栏丢失的原因及解决办法

    症状 在MicrosoftVisio中,您可能会遇到一个或多个以下症状: 您所了解的工具栏是启用是不可见的。 找不到菜单栏。 按钮从工具栏中消失了。   原因 如果您意外地拖动工具栏或菜单栏可见屏幕区域之外,则会出现这些症状。如果满足下列条件之一为真,则也会发生类似问题: 显示分辨率是太低,无法显示工具栏上的所有按钮。 两个工具栏停靠在同一行上相邻。在这种情况下Visio会隐藏一些按钮。   解决方案 若要恢复工具栏或菜单栏,使用下列方法之一: 将显示分辨率设置为800x600或更高。 在已有其自己的行上显示每个工具栏。 还原默认设置。若要这样做,请按照下列步骤。警告如果您修改注册表错误地使用注册表编辑器或使用另一种方法,则可能会出现严重问题。这些问题可能需要重新安装操作系统。Microsoft不能保证可以解决这些问题。修改注册表的风险由您自己承担。 退出Visio的所有实例。 单击 开始、单击 运行,键入 regedit,然后单击 确定。 单击下面的注册表子项以适合您所运行的Visio的版本: Micro

  • Day66~(Redis)67

    redis 背景 例如,08年北京奥运,网上售票崩溃,12306购票崩溃 像一些网站的崩溃,都是因为,高并发,用户量比较大,而当时使用的是关系型数据库。关系型数据库,存在于磁盘中,那么要到cpu中计算需要 cpu—catch—-内存—–磁盘 而磁盘的io性能较低, 关系型数据库的数据逻辑关系复杂,不是适合做大规模集群 解决思路 降低磁盘IO次数,越低越好 去除数据关系。 故出现了在内存中存储,且不存数据关系,这就是Nosql,泛指非关系型的数据库,是对关系型数据库的补充。 常见的Nosql数据库 redis,hbase,MongoDB,memcache Redis特征 1.数据间没有必然的关联关系。 2.内部采用单线程机制进行工作。 3.高性能。 4.多数据类型支持String,list,hash,set,sorted_set 5.持久化支持,可以进行数据灾难恢复 Redis应用 为热点数据加速查询(主要场景),如热点商品,热点新闻,热点资讯 任务队列,秒杀,抢购,购票排队 即时信息查询,如各种排行帮,网站访问统计,公交到站信息,在线人数信息,设备信号等 时效信息控制,

  • Jetbrains Rider:缺少.NET Framework 4.5.2

    前提:由于我们是应用程序的开发者,所以我们要下载的是SDK或者DeveloperPack;而不是Runtime包(runtime是给应用程序的用户使用的)。 前提2:SDK安装完毕后,Rider的反应可能并不那么及时。建议在安装SDK前就关闭Rider哦。 问题1:使用Rider打开一个老的项目,项目目录出现一堆波浪线、下方EventLog告诉我们缺少了:.NETFramework4.5.2(具体缺少哪个版本根据你的项目的实际情况而定); 这是因为我们没有安装该.NETFrameWork开发版本的SDK。解决方案如下: 确定你缺哪个版本,然后到微软官网去下载。VisualStudioSDKs下载地址 记得选择开发版,我这儿缺的是4.5.2;所以我选了4.5.2developerpack. 下载好之后,就是安装了:直接点击下一步就好;安装完毕这个.NETFrameWork4.5.1安装到哪儿了: 再次打开Rider中,右击项目名--选择BulidSelectedProjects,就ok了。 如果编译成功了,但是Rider中的项目还是会一堆波浪线?没关系,重

  • 小结

    1、DropDownList 今天在调试一个代码,发现了一个bug,下拉列表绑定的问题。 DadatValueFiled必须唯一,否则选中的值会自动选中,多个相同值中的第一个值。必须选择一个具备唯一的值进行绑定。

  • 简单爬虫-爬贴吧图片

    #coding=utf-8 #urllib模块提供了读取Web页面数据的接口 importurllib #re模块主要包含了正则表达式 importre #定义一个getHtml()函数 defgetHtml(url): page=urllib.urlopen(url)#urllib.urlopen()方法用于打开一个URL地址 html=page.read()#read()方法用于读取URL上的数据 returnhtml defgetImg(html): reg=r'src="(.+?\.jpg)"pic_ext'#正则表达式,得到图片地址 imgre=re.compile(reg)#re.compile()可以把正则表达式编译成一个正则表达式对象. imglist=re.findall(imgre,html)#re.findall()方法读取html中包含imgre(正则表达式)的数据 #把筛选的图片地址通过for循环遍历并保存到本地 #核心是urllib.urlretrieve()方法,直接将远程数据下载到本地,图片通过x依次递增命名 x=0 forimgurlinimgl

  • 在树莓派上编译安装golang环境

    请看我在掘金的文章

  • php 3des加密 兼容JAVA 多么痛的领悟呀

    最近和别人做接口用到SOCKETTCP/IP方式 其中需要对账号和密码进行3DES加密 对方提供了一个加密比对的软件和JAVA的实现代码 并且给了我们一个长度为32位的密钥 这边需要用PHP来实现! PHP 3des加密的密钥位24位!关于这个密钥长度的问题纠结了很久 最后被哥蒙对了! 32位长度如何转化为24位呢 我是这样做的 将32位的前16位取出来放到后面这样32+16=48位 然后用 $key=pack('H48',$key) 复制  正好是24位! 也就是16进制转化为字节流 这也是有依据的,这种叫着对称加密 当然加密的方式为cbc模式 cbc模式加密是需要一个向量来增加安全性的 看JAVA代码如下   IvParameterSpeciv=newIvParameterSpec(newbyte[]{0,0,0,0,0,0,0,0}); 复制  这样就看到JAVA中的向量是用字节数组表示的! 但是在PHP中该如何表示呢 当然需要先将此字节数组转化成16进制字符串 在php中就是 0000000000000000(在实际运算中中间的空

  • JavaScript 模拟重载

        /** *参数个数对应各自处理的函数不指定则执行默认函数 *[ *d:function(){} *,0:function(){} *,1:function(a){} *,2:function(a,b){} *,3:function(a,b,c){} *,4:function(a,b,c,d){} *] */ !function() { var _reload=(function() { var _default=function(){}//设置默认函数 ;returnfunction(funcs,_def) { ;funcs=funcs.slice()//配置处理函数slice防外部修改 ;funcs["d"]=_def||_default//配置默认函数 ;returnfunction() { ;return(funcs[arguments.length]||funcs.d).apply(this,arguments) } } })() ,test=_reload( [ function(){return0} ,function(x){retur

相关推荐

推荐阅读