zhangcy

2018小结

本文是一个逃避者的自白

今年经历了很多事情,感觉人生轨迹发生了巨大的变化,我感觉是时候写一个总结了。

简而言之,如同180度的大转弯,我放弃了在CV圈的所有知识和成果,义无反顾的投身进了工业界。

其一

18年的开始,是伴随着一堆考试开始的。在只有专业课的大三学期,同时还在实验室和CV圈的神仙斗智斗勇,考试周的到来让我猝不及防。

先是一堆大作业 图形学 智能终端 MUA JAVACAD
然后是一堆硬核考试 操作系统 JAVA 方法学 视觉 network

图形学 糊了一学期的游戏引擎算是写的不错 第一次设计这样大型的C++系统 最后也是拿了100的project分数

智能终端 写了一个智障类暗黑三ARPG游戏 看起来老师挺喜欢的

MUA 又是一个解释器 大学写了成吨的解释器 已经没什么挑战了

JAVACAD 2小时速成MVC Swing UI

OS 这门课 超有意思 我甚至刷完了考研OS复习手册 最后虽然很残念只有94

视觉 全靠背

JAVA 全靠汪大佬提携

方法学 复习了一天就满了 不是很懂这个课的出题思路

Network 这门课可以说是这学期最迷的一门课了 期末破罐子破摔 和老段把往年题抄到A4上 结果成了全班最高分 正态分布后满了 我也是醉了

汇编 水水过了

最后没想到,这学期虽然精力全在CV圈科研上了,最后反倒混到了一等奖学金

其二

和四先生 安先生 西先生 小先生等计划了一次名义上是社会实践,实际上是美食探访的广州旅行。

四先生很懂,基本上吃是由四先生一手包办的,小先生病倒了,我和安先生每天过着快乐的生活,甚至复习了箱学,十分感动,无论是多少次看到箱学,都能打动到我。在我正式入职之前,一定会重新看一遍箱学的。

和四先生、安先生又重温了夏日大作战,第一次看这个剧场版的时候,我还离CS非常遥远,现在作为senior CS student重温经典,感受则截然不同,身上的使命感又重了起来。作为工科的一员,为社会创造价值,提升人类劳动的效率,让信息交换更加通畅,令工厂、学校、交通稳定运行,使知识和文化传递给普罗大众,这就是我们的工程师的使命吧。即使是过了20年,成为了老年人,也不希望自己成为,通过收割韭菜、赚差价而养活自己的人。

广州的食物是真的好,如果有机会,我希望未来居住的地方附近,可以吃到广式早茶。

社会实践散团后,到深圳开始了养老,补番,写了一个失败的JVM(浪费了10天 删光了代码 深感CPP能力不足),最后咸鱼到天天爬塔,可能是我今年 最灰暗的一段时间。

后来于先生跟我说,他找了实习,问我要不要也找找实习。我觉得很好,在深圳的最后几天,便改起了简历,刷起了leetcode,只刷了20道就回了杭州。

其三

回了杭州之后,首先是CVPR中了,还行(说好的糊一个网站,后来鸽了。。),然后继续刷leetcode,然后参加leetcode contest,感觉leetcode contest这个设定很带感,很有趣,很值得参加。

这期间投了腾讯 阿里 网易和微软四家,然后就是开始了无尽的面试,然后四家都拿到了实习的offer。

作为肥宅,肯定是不愿意移动身子,杭州肯定是近水楼台先得月,而且,阿里还有于先生,总不至于孤军奋斗,于先生说他们组很有趣,做的东西很challenging,很有impact。很好,那就去了阿里。

这时候UIUC给了我admission,这个就很尴尬了,没想到还真的能录了,这就开始了纠结。

仔细想了一下之后,先去阿里实习之后再说吧。

其四

阿里的这五个月是最令我震惊的几个月。

鉴于保密因素,大概是不能透露在阿里干了什么。

第一个月在写c++
第二个月在写python和js,中间穿插了java
后面又一直在写c++

去年去中科院实习的日常是,我还要教博士和硕士linux常识。在实验室和浙大的一起工作的时候,周围的同学在programming方面也非常普通。在15CS的其他人里,programming强的人也是屈指可数的。

但是阿里的同事水平都非常高,主管水平也非常高,每天都能从他们那里学到新东西。里面还有几个非常强的大佬,我已经能看到,5年后他们必然是业界的顶梁柱。

这让我对工业界的产生了全新的认识,没想到工业界的大佬是这么强,代码是那么solid,学术界的东西是那么虚,在搞cv的时候就意识到了,cvpr里绝大多数paper在工业场景都是不work的,可能都是真空中的球形paper。

之前认识的同学绝大多数都是学术圈的同学,这可能让我对工业界有了一种bias,自己到了之后,看法却totally change了。我感觉,这种脚踏实地的感觉和在cv圈的感觉是完全不一样的。我个人,更喜欢这种,为社会创造价值的感觉,希望自己的工作真正的,提升社会的便利程度,让我们的生活水平变高。

其五

离开CV圈的思考过程,是很艰难的。

什么样的人适合读PhD?我适不适合读PhD?这些问题其实只有自己感受了工业界,也感受了学术界之后,才能回答。而且真的是所有人都适合读PhD吗?

一个人如果读PhD,那么他的核心竞争力是什么?

不是写代码,不是数学,也不是”技术水平“
越来越多的证据对我表明,sell idea的能力和connection,才是PhD的本质和核心竞争力。

成功的PhD选手,一定是社交能力强的人。现在的学术圈背景下,没有connection的PhD,就相当于职业自杀。你的理论没有人接受,你的论文没有人喜欢,这样的人是在学术圈混不下去的。

从PhD的申请开始,到PhD的毕业,这个过程中,知识、技术水平、实践能力的影响微乎其微。从申请一开始,擅长communication和networking的人,就取得了胜利了。

至于我自己,作为肥宅和一个比较自闭的人,很显然,PhD是不适合我的。

最后下了决心,离开了实验室,简历里删掉了所有CV相关的内容,我相信,我是不会继续搞这种东西了。

其六

实习结束了,做的东西非常有成就感,最后也成功上线,带着愉快的心情,飞往了北美,结果一下飞机就进了小黑屋,奠定了这四个月的悲伤基调。

在美国的四个月,是很悲伤的,就像是一个城里人来到了农村,一切都是不方便的。

美国人喜欢的东西,我都不喜欢,不喜欢运动,不喜欢party,不喜欢美剧,不喜欢远足。

美国这个地方,只会让自闭的肥宅更加自闭。

强忍着悲伤、恐惧和不安,在这个未知的地方,我还是要考虑毕业之后的打算。找到一个实习便是重中之重了。

投了很多家,比春招的时候多得多,抓住一切可以投的机会,career fair,after hour,网申,内推,linkedin。

每天也在刷题,孤独的刷题,然后收到一堆rej,每天越来越绝望和自闭。这时候幸好认识了邓先生,邓先生有时候会陪我刷刷题,约饭,陪我度过了这段最艰难的时光。

然后就是rej越来越多,面试的时候,英文太差,听不懂面试官在讲啥,自己的口语也是磕磕绊绊,题有时候还做不出来,每天只能看傻屌视频来掩饰自己的悲伤。

然后转机来了,拿到了tusimple的offer,他们家是中文面试的,所以面试的过程,我很有把握,也很有自信,最后果不其然拿了offer。

拿了offer之后很犹豫,不知道该不该接。曾经一度想接了offer,周伟的人却劝我坚持一下。我想了想,大不了拒了offer拼一下吧。

但是tusimple的HR,竟然帮我延期了一周,这个让我非常感动,我觉得这家公司还是非常靠谱的,2019年的这个时候回来看,发展的的确是非常好的一家公司。

在延期的这段时间,我继续刷题,刷题,刷题然后。。。拿到了facebook的offer。

突然感觉如释重负,仿佛实现了一个小目标一样。

其七

在实习尘埃落定之后,就已经是11月份了,开始了百无聊赖的养老生活。

Continue
吹学杂谈

从昨天(12.17)开始看吹学之后,就一直想写一篇文章来探讨一下,我个人对吹学小故事的一些思考感悟,这篇文章应该会持续更新,直到我看完吹学为止吧。

吹学杂谈几乎不涉及吹学本身,没有剧透,可以放心观看。

其一

前辈和后辈,是日本社会绕不过的一个话题。虽然韩愈先生早在一千多年前就写下”闻道有先后,术业有专攻“,可是这个看着简单的道理,背后隐藏着复杂的社会问题。比起中国和欧美国家,在日本,这个问题是尤为严峻的,而且随着经济发展的停滞,矛盾变得越来越凸显。

在中国,国企和事业单位固然是有排资论辈的传统的,升职要按照入职时间排序,分房一样的福利也是先来先得,这是共产主义的均分传统在社会主义市场经济下的一些遗产。但是我们总体来说,这个问题根本不算是我们社会上的主要矛盾,甚至连矛盾都算不上。

然而,在日本,情况的严峻会让我们瞠目结舌。最近的一则新闻”日本社长把员工的脸按进火锅取乐“,让很多中国人第一次感觉到了这种文化的恐怖之处。如果在日本生活过,或者对日本文化了解比较深入的人,对这种现象的产生,可能也许就见怪不怪了。

日文中有一种文法,叫做敬语。敬语和中文中的敬语不能混为一谈。中文语境的敬语,只是一些零散的固定搭配;日文文法中的敬语,则是一套成体系的,有多重不同尊敬程度的,影响语言中绝大多数表达的文法系统。

对于敬语,在日本是褒贬不一的一种事物,我个人可能倾向于把它比作日本的“种姓制度”,虽然没有印度的种姓制度那么恶劣,但是对这个日本社会,对日本文化,对日本人的精神上,都留下了不可磨灭的烙印。

为什么要提到敬语?因为敬语是体现日本社会阶级性质的重要体现之一,一个日本人和不同的人说话之前,都要首先揣摩自己和对方的地位大小,阶级高低,辈分先后,使用不同的敬语(在日本服务行业的敬语的特殊使用,我们暂且按下不表)。举一个小小的例子,对于吃(食べる)这个动词,常见的表达就有这么多种:

日文表达 类型 用法 汉语翻译
食べる 原形 随意的表达
食べます 丁宁语 常见,正式的表达
いただく 谦让语 用以自谦
召し上がる 尊敬语 表达尊敬 请吃

对于什么时候该使用哪种敬语,是被限定住、不可修改的规则。如果你的同事入职比你早一天,那他就是你的前辈,而且一直是你的前辈;如果你是一年级同学,那么二年级同学永远对你就是前辈。对于前辈,你要使用更加尊敬的语言,而且要接受前辈对你使用不是那么尊敬的语言。

在语法之上,还有语言,后辈是不能和前辈顶嘴的,而且前辈是可以教育后辈的,没有任何其他原因,只是因为前后辈而已。

在语言之上,还有行为,对于荣誉,前辈是优先获得;对于过错,后辈要首先背锅;对于机会,首先考虑的是前辈;对于要做的事情,那一定是后辈做的更多。

这种压抑的文化改变了很多日本人的性格,也改变了整个社会的氛围。谁想打破这套规则,谁就会被绝大多数人所敌视。

在这套规则下,日本的年轻人,不再想去奋斗;有能力的人,会磨平自己的棱角;有理想的人,会隐忍的熬资历;被现实生活击垮的人,则会放纵自己,寄托于虚拟世界,在社会中营造出了“娱乐至死”的风气。

但这种文化,并不是凭空出现的。

在生活中,我们可能见得太多了,年龄和资历小于自己,能力却远大于自己的人。这种情况,比同辈压力,更容易让人精神上崩溃。这是一种对自己过去的否认,对自己现在的焦虑,对自己未来的迷茫。所以,前辈,或者说是资历比较深的人,必然是要有一种,自我保护的手段。他们通过设立行业门槛,资历门槛来限制年轻的人中有能力的人对资源的占有率,从而可以让这个集体内部,不会出现所有资源都倾斜到最优秀的几个人身上的情况。

问题的表象是前后辈之争,然而本质是另一个问题,那就是在一个资源有限的集体中,资源应该如何分配?

很可惜,马克思先生在两百年前就给出了答案,这个问题是无解的。

这个世界的资源是有限的,每个人都想占据更多的资源,你占据多了势必有个人就会减少,这就产生了阶级,产生了阶级矛盾。

  • 平均分配?生产力大幅度降低。
  • 能力分配?马太效应,资源集中,社会动荡。
  • 按生产资料分配?阶级固化。
  • 按需分配?我希望在2100年能实现。

没有一种理想的分配方式,我们就只能寻找现实的分配方式。

— ”实行按劳分配为主体、多种分配方式并存的制度,把按劳分配和按生产要素分配结合起来,可以调动各方面的积极性,促进经济效率的提高,推动生产力的发展。“

Continue
一个说明

这个blog充满中二病,没有任何干货,请谨慎观看。

也许会有一丢丢技术文章。

Continue
用JavaScript写一个地牢游戏地图生成器

今天用JavaScript写一写这个,类似DNF的这种地图的自动生成器,效果如上图所示。

架构

这个我们就采用简单的MVC的架构

Model:

1
2
3
let Rooms = [];   // 房间地图 M * M
let HRoads = []; // 房间之间横向道路 M * (M - 1)
let VRoads = []; // 房间之间纵向道路 (M - 1) * M

View:

1
<canvas width="500" height="500" style="border:1px solid black;" id="screen"></canvas>

Controller:
通过function drawMap()将Model同步到View上

画地图

我们利用canvas的2d context,可以很轻松的画出地图

1
2
3
4
5
6
7
8
// 画一个房间矩形
const canvas = document.getElementById('screen');
const context = canvas.getContext('2d');
context.fillRect(
j * (RoomLength + RoadLength),
i * (RoomLength + RoadLength),
RoomLength,
RoomLength);

以此类推

生成地图

生成地图我们采用简单的DFS算法。

首先我们生成一条一本道,也就是dfs的第一条分支我们是一定走通的,
然后通过限制深度,我们可以得到一条特定长度的主干路线,我们在
这条路线的两端标记为起点和重点。

然后我们在第二条分支开始,设置一个概率,然后随机选择是否分枝,
这样可以创建岔路。

还有一点就是,我们可以创建环路,这可以再设置一个概率,然后选择
是否和已有方块接壤来控制。

值得一提的是,我们可以把起点设置为单出口,这很简单,可以通过设置一个flag实现。

实现参考后面的代码实现。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<label>MeshLength<input id="MeshLength" value="6"/></label>
<label>NextRatio<input id="NextRatio" value="0.5"/></label>
<label>CircleRatio<input id="CircleRatio" value="0.1"/></label>
<br/>
<label>DeepTotal<input id="DeepTotal" value="5"/></label>
<label>RoomTotal<input id="RoomTotal" value="10"/></label>
<button onclick="onClick()">Generate</button>
<br/>
<canvas width="500" height="500" style="border:1px solid black;" id="screen"></canvas>
<style>
</style>
<script>
// Draw Parameter
const RoomLength = 30;
const RoadLength = 10;
const RoadWidth = 5;

let MeshLength = 5;
let DeepTotal = 5;
let RoomTotal = 10;
let NextRatio = 0.5;
let CircleRatio = 0.1;

let Rooms = []; // M * M
let HRoads = []; // M * ( M - 1 )
let VRoads = []; // ( M - 1 ) * M

function getRandomInteger(l, r){
return parseInt(Math.random() * (r - l + 1)) + l;
}

function initialize() {
Rooms = [];
HRoads = [];
VRoads = [];
for(let i = 0; i < MeshLength; i++) Rooms.push([]);
for(let j = 0; j < MeshLength; j++) HRoads.push([]);
for(let j = 0; j < MeshLength - 1; j++) VRoads.push([]);
}


const dx = [0, 0, -1, 1];
const dy = [1, -1, 0, 0];
const dr = [1, 0, 0, 1];

let RoomNow = 0;
let isStart = 0;
let isEnd = 0;

function dfs(deep, x, y, isSingle){
let flag = 1;
RoomNow --;
if( !isStart ){
Rooms[x][y] = 2;
}
else if( !deep && !isEnd){
isEnd = 1;
Rooms[x][y] = 3;
}
else {
Rooms[x][y] = 1;
}
isStart = 1;
for(let i = 0; i < 4; i++){
if( deep == 0 || RoomNow == 0) return;
const tx = x + dx[i];
const ty = y + dy[i];
if( tx >= 0 && ty >= 0 && tx < MeshLength && ty < MeshLength
){
if(!Rooms[tx][ty] && (flag == 1
|| Math.random() <= NextRatio)){
if ( i < 2 ){ // Horizontal
HRoads[tx][ty-dr[i]] = 1;
}
else{
VRoads[tx-dr[i]][ty] = 1;
}
flag = 0;
dfs(deep-1, tx, ty, 0);
if(isSingle) return;
}
else if(Rooms[tx][ty] == 1 && Math.random() <= CircleRatio){
if ( i < 2 ){ // Horizontal
HRoads[tx][ty-dr[i]] = 1;
}
else{
VRoads[tx-dr[i]][ty] = 1;
}
}
}
}
}

function generateMap(){
MeshLength = document.getElementById('MeshLength').value;
NextRatio = document.getElementById('NextRatio').value;
DeepTotal = document.getElementById('DeepTotal').value;
CircleRatio = document.getElementById('CircleRatio').value;
RoomTotal = document.getElementById('RoomTotal').value;
initialize();
RoomNow = RoomTotal;
isStart = isEnd = 0;
dfs(DeepTotal,
getRandomInteger(0, MeshLength - 1),
getRandomInteger(0, MeshLength - 1),
1
);
}

function drawMap(){
const canvas = document.getElementById('screen');
const context = canvas.getContext('2d');
context.clearRect(0,0,20 * (RoomLength + RoadLength),
20 * (RoomLength + RoadLength));

// Draw Room
for(let i = 0; i < MeshLength; i++){
for(let j = 0; j < MeshLength; j++){
if(Rooms[i][j]){
if(Rooms[i][j] == 1) context.fillStyle = '#FF0000';
else if(Rooms[i][j] == 2) context.fillStyle = '#0FFFF0';
else if(Rooms[i][j] == 3) context.fillStyle = '#3731ee';
context.fillRect(
j * (RoomLength + RoadLength),
i * (RoomLength + RoadLength),
RoomLength,
RoomLength);
}
}
}

// Draw Horizontal Road
for(let i = 0; i < MeshLength; i++){
for(let j = 0; j < MeshLength - 1; j++){
if(HRoads[i][j]){
context.fillStyle = '#00FF00';
context.fillRect(
j * (RoomLength + RoadLength) + RoomLength,
i * (RoomLength + RoadLength) + (RoomLength - RoadWidth) / 2,
RoadLength,
RoadWidth);
}
}
}

// Draw Vertical Road
for(let i = 0; i < MeshLength - 1; i++){
for(let j = 0; j < MeshLength; j++){
if(VRoads[i][j]){
context.fillStyle = '#00FF00';
context.fillRect(
j * (RoomLength + RoadLength) + (RoomLength - RoadWidth) / 2,
i * (RoomLength + RoadLength) + RoomLength,
RoadWidth,
RoadLength);
}
}
}

}

function onClick(){
initialize();
generateMap();
drawMap();
}

</script>
</body>
</html>
Continue
Home Archives Tags About Search