Caffe中梯度(Gradient)的检验方法

在caffe中定义了新的layer后,需要在test文件夹下定义对应的unittest函数,以检验layer在forward和backward计算过程中的正确性。

定义forward的测试函数很容易,参考任意一个layer的测试文件(例如test_euclidean_loss_layer.cpp),只需手动计算一遍结果,再和layer计算出来的结果进行对比即可。

backward的测试函数不那么直观,函数中没有任何手动计算相关的过程,核心只有一行:

checker.CheckGradientExhaustive(&layer, this->blob_bottom_vec_, this->blob_top_vec_);

查看了函数的源代码才发现,caffe采用了差分法(Finite difference method)来验证梯度的计算,用数值方法来确保backward梯度计算的正确性。

Caffe中的set_cpu_data函数

此函数略坑爹,没有文档说明。其效果是:改变Blob中的数据指针,指向函数参数所给的值。而不是数据拷贝。

The set_cpu_data() function only modify the data pointer of the Blob to the given location. In other words, it only modify the reference but doesn’t copy the data.

梦的算法?

纯粹是因为开始翻《梦的解析》后产生的一点想法。

书里边说,成为梦里边的主题的,往往是平常不经意间发生在身边的,而不是我们有意关注的事情。也就是说,记忆的形成与注意力这个东西可能存在于两条相对独立的信息处理通路(?)。有可能感官信息收集和记忆的形成过程相,相当于是对“输入数据”的全局采样。对于不经意接收到的信息的处理,这里可能又有两个猜测:1、是识别“建模”后再存入记忆,做梦时直接得到的就是“模型”;2、还是存入记忆的是全景数据,做梦时再调用出来,做一次识别(做梦的过程很像完整的感知过程,不同的是,感官数据的来源很大一部分来源于记忆,比如视觉)。

关于机器感知,通常只一次性采集所关注的信息。抛开机器感知这个话题,考虑漫无目的的记忆的形成方式,是不是可以有类似的算法,全局采集数据,模拟梦的形成方式?

可以去关注一下记忆的形成方式。。

高精度加减乘除法(不压位及压位)

今天凌晨3:30,终于实现了我学习OI一来的一个夙愿:写高精度除法,并较好的实现了压位操作以及与之配套的输入输出操作。贴代码纪念一下:
1、无压位操作的

#include 
#include 

/*
大整数储存方式:
	1、a[0]存位数
	2、a[1]、a[2]……依次存个位、十位……(倒序,个位在a[1]对齐)

这样存的话,中间关于位置的计算全都不用带MAXL,个位对齐方便
*/

#define MAXL 500

void Hi_Add(int a[], int b[], int c[]);//加法
void Hi_Sub(int a[], int b[], int c[]);//减法
void Hi_Mul(int a[], int b[], int c[]);//乘法
void Hi_Div(int a[], int b[], int c[]);//除法,感觉还是不太容易直接调用Hi_Sub函数,所以给除法单独写了个Hi_Div_Sub减法函数
int Hi_Div_Cmp(int a[], int b[]);//供除法调用的比较函数
void Hi_Div_Sub(int a[], int b[]);//供除法调用的减法函数,指针很容易实现对位
void print(int a[]);//打印大整数
void swap(int *a, int *b);

int a[MAXL]={0},b[MAXL]={0},c[MAXL]={0};
char operater;

void init()//这是读入部分,把表达式拆开,格式和C++有点不一样,领会意思就行了
{
	char ch;
	int i;
	while (scanf("%c",&ch),ch>='0'&&ch='0'&&ch<='9') b[++b[0]]=ch-'0';
	for (i=1; i<=a[0]/2; i++) swap(a+i,a+a[0]+1-i);
	for (i=1; ib[0] ? a[0]:b[0];//c位数初始化
	for (i=1; i<=c[0]; i++)
	{
		c[i]+=a[i]+b[i];
		c[i+1]+=c[i]/10;
		c[i]%=10;
	}
	if (c[c[0]+1]) c[0]++;//如最高位有进位
}

void Hi_Sub(int a[], int b[], int c[])
{
	int i;
	memset(c,0,sizeof(c));
	c[0]=a[0];
	for (i=1; i<=c[0]; i++)
	{
		c[i]+=a[i]-b[i];
		if (c[i]1) c[0]--;//去掉高位的0,注意,如果结果是0,个位的0要保留(位数至少为1,下同)
}

void Hi_Mul(int a[], int b[], int c[])
{
	int i,j;
	memset(c,0,sizeof(c));
	c[0]=a[0]+b[0]-1;
	for (i=1; i<=a[0]; i++)
		for (j=1; j1) c[0]--;//万一有个乘数是0的情况,位数会减少,去0
}

void Hi_Div(int a[], int b[], int c[])
{
	int i;
	memset(c,0,sizeof(c));
	c[0]=a[0]-b[0]+1;//商最高位不超过a[0]-b[0]+1,c位数初始化一下
	for (i=a[0]-b[0]+1; i>0; i--)
		while (Hi_Div_Cmp(a+i-1,b)>=0)//用指针,对齐待减的部分和b的个位(联想竖式除法)
		{							  //其实可以完全不用为试除作乘法,在当前位一直减就可以了,直到减不动为止(时间效率理论上比乘法试除要高)
			Hi_Div_Sub(a+i-1,b);      //每对a减一次,就在c的对应位+1(a中不断地减去b的倍数,最后剩下的就是余数)
			c[i]++;
		}
	while (c[c[0]]==0&&c[0]>1) c[0]--;
	while (a[a[0]]==0&&a[0]>1) a[0]--;//剩下的a作为余数,化为标准大整数形式,以备输出
}

int Hi_Div_Cmp(int a[], int b[])//比较函数,看是否还能再做减法
{
	int i;
	for (i=b[0]+1; i>0; i--)
	{
		if (a[i]>b[i]) return 1;
		if (a[i]<b[i]) return -1;
	}
	return 0;
}

void Hi_Div_Sub(int a[], int b[])//除法专用的减法,普通减法稍稍改了一下
{
	int i;
	for (i=1; i<=b[0]; i++)
	{
		a[i]-=b[i];
		if (a[i]0; i--) printf("%i",a[i]);
}

void swap(int *a, int *b)
{
	int c;
	c=*a;
	*a=*b;
	*b=c;
}

2、经过压位操作的

//这是经过压位的大整数计算,比较一下,其实主过程和普通几乎一样
//不一样的地方:1、所有跟10进制有关的地方都改成UPPERBOUND控制(可以改成10,100,10000...),同时对应的位数DIGITS也要改
//              2、打印大整数部分会有些不同
//				3、读入时处理复杂一些
//				4、优点:加减乘运算减少运算次数,压位后空间利用率变高
//				5、缺点:读入和输出稍复杂,除法每次作差试除效率变低

#include 
#include 

/*
大整数储存方式:
	1、a[0]存位数
	2、a[1]、a[2]……依次存个位、十位……(倒序,个位在a[1]对齐)

这样存的话,中间关于位置的计算全都不用带MAXL,个位对齐方便
*/

#define MAXL 500
#define UPPERBOUND 10000
#define DIGITS 4

void Hi_Add(int a[], int b[], int c[]);//加法
void Hi_Sub(int a[], int b[], int c[]);//减法
void Hi_Mul(int a[], int b[], int c[]);//乘法
void Hi_Div(int a[], int b[], int c[]);//除法,感觉还是不太容易直接调用Hi_Sub函数,所以给除法单独写了个Hi_Div_Sub减法函数
int Hi_Div_Cmp(int a[], int b[]);//供除法调用的比较函数
void Hi_Div_Sub(int a[], int b[]);//供除法调用的减法函数,指针很容易实现对位
void print(int a[]);//打印大整数

int a[MAXL]={0},b[MAXL]={0},c[MAXL]={0};
char operater;

void init()//这是读入部分,把表达式拆开,格式和C++有点不一样,领会意思就行了。有兴趣可以认真读一下。
{
	int temp[MAXL]={0},i,mask;
	char ch;

	while (scanf("%c",&ch),ch>='0'&&ch<='9') temp[++temp[0]]=ch-'0';

	operater=ch;

	for (i=1; i='0'&&ch<='9') temp[++temp[0]]=ch-'0';
	for (i=1; ib[0] ? a[0]:b[0];//c位数初始化
	for (i=1; i<=c[0]; i++)
	{
		c[i]+=a[i]+b[i];
		c[i+1]+=c[i]/UPPERBOUND;
		c[i]%=UPPERBOUND;
	}
	if (c[c[0]+1]) c[0]++;//如最高位有进位
}

void Hi_Sub(int a[], int b[], int c[])
{
	int i;
	memset(c,0,sizeof(c));
	c[0]=a[0];
	for (i=1; i<=c[0]; i++)
	{
		c[i]+=a[i]-b[i];
		if (c[i]1) c[0]--;//去掉高位的0,注意,如果结果是0,个位的0要保留(位数至少为1,下同)
}

void Hi_Mul(int a[], int b[], int c[])
{
	int i,j;
	memset(c,0,sizeof(c));
	c[0]=a[0]+b[0]-1;
	for (i=1; i<=a[0]; i++)
		for (j=1; j1) c[0]--;//万一有个乘数是0的情况,位数会减少,去0
}

void Hi_Div(int a[], int b[], int c[])
{
	int i;
	memset(c,0,sizeof(c));
	c[0]=a[0]-b[0]+1;//商最高位不超过a[0]-b[0]+1,c位数初始化一下
	for (i=a[0]-b[0]+1; i>0; i--)
		while (Hi_Div_Cmp(a+i-1,b)>=0)//用指针,对齐待减的部分和b的个位(联想竖式除法)
		{							  //其实可以完全不用为试除作乘法,在当前位一直减就可以了,直到减不动为止(时间效率理论上比乘法试除要高)
			Hi_Div_Sub(a+i-1,b);      //每对a减一次,就在c的对应位+1(a中不断地减去b的倍数,最后剩下的就是余数)
			c[i]++;
		}
	while (c[c[0]]==0&&c[0]>1) c[0]--;
	while (a[a[0]]==0&&a[0]>1) a[0]--;//剩下的a作为余数,化为标准大整数形式,以备输出
}

int Hi_Div_Cmp(int a[], int b[])//比较函数,看是否还能再做减法
{
	int i;
	for (i=b[0]+1; i>0; i--)
	{
		if (a[i]>b[i]) return 1;
		if (a[i]<b[i]) return -1;
	}
	return 0;
}

void Hi_Div_Sub(int a[], int b[])//除法专用的减法,普通减法稍稍改了一下
{
	int i;
	for (i=1; i<=b[0]; i++)
	{
		a[i]-=b[i];
		if (a[i]0; i--)
		if (i==a[0]) printf("%i",a[i]);
		else                           //中间部分高位出现0,必须用0补齐
		{
			x=a[i];
			while (mask>0)
			{
				printf("%i",x/mask);
				x%=mask;
				mask/=10;
			}
		}
}

POJ 1011 Sticks (Central Europe 1995)解题报告

现在搜索剪枝优化能力明显不如当年了。这么一道以前做过的题,不是搜索策略出错WA,就是优化不到家TLE。好不容易翻出以前的Pascal程序,翻译成了C,勉强AC了。

1、首先,预处理用背包算出所有可能达到的长度;

2、用计数排序优化(因为长度<=50,木棍数<=64,枚举长度比枚举木棍代价低?);

3、类似迭代加深搜索,枚举原始长度进行判断;

4、对于每根原始木棍,必选当前最短没被用到的木棍,枚举其余木棍按长度升序枚举,每组成一根原始木棍就不再改变已使用的木棍的状态。

这些对于测试数据足矣,不过对于传说中的BT64数据,还是得花接近10s才能出解。

基础计算几何题三道

这周一的计算概论课上,我第一次走上了讲台,奉峰哥之命,给大家讲了讲计算几何的基础。讲完后,我发现其中有几个地方没讲得太清楚,下面的解题报告中会提及部分的问题。

1、Intersecting Lines

这道题是直线的问题,用不上叉积之类的,普通的解析几何做就可以了。

先根据点的坐标求出形如Ax+By+C=0的直线方程的系数,然后根据A1/A2,B1/B2,C1/C2判断是否平行或者重合。如果既不平行也不重合,就可以直接代入手工解出来的交点公式算交点坐标。

2、Wall

最基本的凸包求解,用Graham算法实现。不过有几个实现细节有几个地方需要注意:

1)按照上课讲的选最下面的一个点(y坐标最小),如果有多个,得选x坐标最小的;

2)如果起点和两个待比较的点的连线共线,则按照坐标升序排列;

3)我当时说是按极角排序,但实际上你会发现,这是一个基于比较的排序。也就是说对于p1和p2,你只需要计算p0p1×p0p2就可以得出p1和p2相对p0的角度位置,而不用算它们的极角。我调用的是stdlib的快排,这些比较问题只需在比较函数里设置好久行了。

3、Will Indiana Jones Get There?

这道题的总体思路是,计算每条线的之间的最短距离(相交的话当然是0),然后调用一次最短路算法(我用的SPFA)。关键问题就是计算两条线段之间的最短连线距离。考虑到这道题所有的点都是水平或者竖直的,而且要算距离,向量之类的东西反而感觉实现起来不太方便,于是我采用的是分三类情况讨论:水平与水平,竖直与竖直,水平与竖直。然后根据端点坐标分别计算距离。

Computational Thinking 计算(机)思维

当你女儿早晨去学校时,她把当天需要的东西放进背包;这就是预置和缓存。当你儿子弄丢他 的手套时,你建议他沿走过的路回寻;这就是回推。在什么时候你停止租用滑雪板而为自己买一对呢?这就是在线算法。在超市付账时你应当去排哪个队呢?这就是 多服务器系统的性能模型。为什么停电时你的电话仍然可用?这就是失败的无关性和设计的冗余性。完全自动的大众图灵测试是如何区分计算机和人类(简称CAPTCHA)的,即CAPTCHAs是怎样鉴别人类的?这就是充分利用求解人工智能难题之艰难来挫败计算代理程序。

这是从一篇名叫《Computational Thinking(计算思维)》摘录下来的一段比喻,个人觉得比较有意思。

原文在这里:www.cs.cmu.edu/afs/cs/usr/wing/www/publications/Wing06.pdf
原文翻译Google上满天飞

以上谨供各位大牛火星我一下~

USACO Numbering the Cows(cownum)

Problem cownum: Numbering the Cows [Romanian Olympiad, 2001]

Farmer John wants to assign a (not necessarily distinct) integer

in the range 1..N (3 <= N <= 1,000) to each of his N cows for

identification purposes. Thus, he lined up all his cows in order

and came up with the following rule: the i-th cow in line must be

assigned an integer that is less than the integers assigned to cows

i+2 and i+3.

FJ wants to know the total number of possible assignments he might

make. If cow i+2 does not exist, then cow i does not have the

constraint that its ID number must be less than that of cow i+2.

Likewise if cow i+3 does not exist.

Since Farmer John is not too good at math and might be confused by

large numbers, output the answer modulo M (1 <= M <= 10,000,000).

PROBLEM NAME: cownum

INPUT FORMAT:

Two space-separated integers: N and M.

SAMPLE INPUT (file cownum.in):

3 10000

OUTPUT FORMAT:

A single line containing the number of assignments modulo M.

SAMPLE OUTPUT (file cownum.out):

9

OUTPUT DETAILS:

There are 9 valid assignments: (1,1,2), (1,1,3), (1,2,2), (1,2,3), (1,3,2),

(1,3,3), (2,1,3), (2,2,3), (2,3,3).

先orz一下xt神牛(虽然我不认识)的神奇DP

设f[i,j]表示前i头牛编号不大于j的方案数

若a[i]<>j,则总数累加f[i,j-1],否则(a[i]=j时),分以下情况累加

i)a[i-2]=a[i-1]时,总数为f[i-2,j-1]

ii)a[i-2]>a[i-1]时,总数为f[i-1,j-1]

iii)a[i-2]<a[i-1]时,总数为f[i-2,j-1]+f[i-2,j-2]+f[i-2,j-3]+…+f[i-2,1](这一处似乎和神牛的题解有些出入,他是从f[i-2,j-2]开始累加的)

边界f[1,k]=k   f[2,k]=n*n

不过现在是O(n^3),所以需要优化:g[i,j]=f[i,1]+f[i,2]+…+f[i,j]

接下来程序验证……(待续)

xt真神牛也,他的方程是对的,我的是错的。这是为什么呢?回去继续研究。

{2009年7月22日0:33:50

看过USACO题解后,终于明白哪里错了

这一句“若a[i]<>j,则总数累加f[i,j-1]”就开始错,因为a[i-1]可能为j

下面重新定义f[i,j]的计算方式:

1、用1~j-1编号这i头牛(f[i,j-1])

2、最后两头牛都为j(f[i-2,j-1])

3、最后一头为j,其他前面的小于j(f[i-1,j-1])

4、倒数第二头为j,最后一头小于j(f[i-2,j-2]+f[i-2,j-2]+f[i-2,j-3]+…+f[i-2,1])

这下就对了

2009年7月22日0:41:08}

下贴上几个月以来第一段程序代码,一年以来第一个C++代码,以及n久以来第一次切题通过记录:

/*
PROG: cownum
LANG: C++
ID: tjbwyk1
*/

#include<fstream>
using namespace std;
ifstream input("cownum.in");
ofstream output("cownum.out");

const int maxn=1002;
int f[maxn][maxn],g[maxn][maxn],n,m,i,j;

void init()
{
input>>n>>m;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
for (i=1; i<=n; i++)
{
f[1][i]=i%m;
f[2][i]=i*i%m;
g[1][i]=(g[1][i-1]+f[1][i])%m;
g[2][i]=(g[2][i-1]+f[2][i])%m;
}
}

void doit()
{
for (i=3; i<=n; i++)
for (j=1; j<=n; j++)
{
f[i][j]=(f[i][j-1]+f[i-2][j-1]+f[i-1][j-1]+g[i-2][j-2])%m;
g[i][j]=(g[i][j-1]+f[i][j])%m;
}
}

void outit()
{
output<<f[n][n]<<endl;
}

int main()
{
init();
doit();
outit();
input.close();
output.close();
return 0;
}

华丽的记录:

USER: Yikang Wang [tjbwyk1]

TASK: cownum

LANG: C++

Compiling…

Compile: OK

Executing…

Test 1: TEST OK [0.022 secs]

Test 2: TEST OK [0.022 secs]

Test 3: TEST OK [0.032 secs]

Test 4: TEST OK [0.022 secs]

Test 5: TEST OK [0.011 secs]

Test 6: TEST OK [0.022 secs]

Test 7: TEST OK [0.022 secs]

Test 8: TEST OK [0.022 secs]

Test 9: TEST OK [0.022 secs]

Test 10: TEST OK [0.054 secs]

Test 11: TEST OK [0.043 secs]

Test 12: TEST OK [0.054 secs]

Test 13: TEST OK [0.043 secs]

Test 14: TEST OK [0.054 secs]

Test 15: TEST OK [0.054 secs]

Test 16: TEST OK [0.065 secs]

All tests OK.

YOUR PROGRAM (‘cownum’) WORKED FIRST TIME! That’s fantastic

— and a rare thing.  Please accept these special automated

congratulations.

Test Data | Analysis

Keep up the good work!

下一个任务由烧白同学指派,Turning in Homework