diff --git a/2021-guangzhou.html b/2021-guangzhou.html index 6485366..e9b8430 100644 --- a/2021-guangzhou.html +++ b/2021-guangzhou.html @@ -139,12 +139,13 @@

2021年广州的风

又在B站听到了“原来你也在这里”

那个夜晚,那些晚风和歌,成为了我一年后关在家里时最想回到的过去

+ \ No newline at end of file diff --git a/about.html b/about.html index 6d3519f..047cd4d 100644 --- a/about.html +++ b/about.html @@ -125,12 +125,13 @@

About me

你好! 👋

我是高赫阳,北京邮电大学计算机科学与技术专业本科生,高中毕业于辽宁省实验中学。

欢迎来到我的秘密基地,这里偶尔会更新我学的新知识、读的新论文还有一些旅游回忆。

通过 email 联系我:gaoheyang1014@gmail.com

+ \ No newline at end of file diff --git a/adversarial-robustness-01.html b/adversarial-robustness-01.html index 03a705a..cfe445e 100644 --- a/adversarial-robustness-01.html +++ b/adversarial-robustness-01.html @@ -243,12 +243,13 @@

[Adversarial Robustness] 1 Introduction to adversarial print(f"Predicted probability: {nn.Softmax(dim=1)(pred)[0, max_class].item()}")
Predicted class: airliner Predicted probability: 0.9099140763282776

和前面一样,这里是我们的飞机猪,看起来非常像一只正常的猪(代码中的目标类别 404 的确是飞机,所以我们的定向攻击起效了)。

plt.imshow((pig_tensor + delta)[0].detach().numpy().transpose(1, 2, 0))

下面是我们的飞机噪声。

plt.imshow((50*delta + 0.5)[0].detach().numpy().transpose(1, 2, 0))

当然,结论是使用对抗攻击和深度学习,你可以让猪飞。

我们稍后会讨论这些攻击引发的实际问题,但这样的攻击的容易性引发了一个显然的问题:我们可以训练出在某种程度上抵抗这种攻击的深度学习分类器吗?这个问题的简短回答是“是的”,但我们(作为一个领域)距离真正实现这样的训练或者几乎达到我们用“标准”深度学习方法获得的性能还有很长的路。这个教程会详尽地包含攻击和防御侧,并希望到它结束时你会对目前发展状况和我们仍要取得大量进展的方向有一个了解。

对抗鲁棒性的简短(不完整)历史

+ \ No newline at end of file diff --git a/bayes.html b/bayes.html index f182b91..1702375 100644 --- a/bayes.html +++ b/bayes.html @@ -165,12 +165,13 @@

贝叶斯模型

P(X_1=x_1,\dots, X_n=x_n) = \prod_{i=1}^n P(X_i=x_i|X_{i+1}=x_{i+1},\dots,X_n=x_n)">p(x1,,xK)=p(xKx1,,xK1)p(x2x1)p(x1)P(X1=x1,,Xn=xn)=i=1nP(Xi=xiXi+1=xi+1,,Xn=xn)p(x_1,\dots,x_K)=p(x_K|x_1,\dots,x_{K-1})\dots p(x_2|x_1)p(x_1) \\ P(X_1=x_1,\dots, X_n=x_n) = \prod_{i=1}^n P(X_i=x_i|X_{i+1}=x_{i+1},\dots,X_n=x_n)

贝叶斯网络的结构形式

+ \ No newline at end of file diff --git a/categories.html b/categories.html index 1e7c37a..eee1fe8 100644 --- a/categories.html +++ b/categories.html @@ -125,12 +125,13 @@

Categories

Machine Learning (4)
Math (2)
MySQL (4)
Memory (3)

+ \ No newline at end of file diff --git a/changsha.html b/changsha.html index e116ca6..4b5ec56 100644 --- a/changsha.html +++ b/changsha.html @@ -139,12 +139,13 @@

长沙吃吃逛逛

决定把去长沙的过程写得详细一点,因为很喜欢长沙,特别是住在河西金融中心人少的地方😂

第一天晚上从大连飞去长沙,在黄花机场第一次坐了磁浮列车,速度和乘坐体验都和北京首都机场线差不多🤣。酒店订在了 4 号线茶子山地铁站附近的全季酒店,旁边是凯德壹中心,里面的茶颜悦色几乎不用排队,很不错😋,柠季的鸭屎香柠檬茶也很好喝。重要的是超级喜欢益阳麻辣烫,特别是加在里面的粉,外卖随便点的臭豆腐也好吃。

第二天早上吃了金融中心附近很贵的炒码面,味道还可以。上午去了湖南博物院,快速参观了湖南历史和辛追夫人展。

女书 @湖南博物院

看了王师傅的视频第一次去吃豪客来牛排,在辽宁和北京都没见过hhh👀 好开心

很像乡里别 @豪客来牛排

晚上去长郡中学看了一下,就在黄兴广场附近,羡慕长郡的高中生买小吃很方便。

冒充长郡高中生 @长郡中学

还顺路去了很多地方啦,比如步行街、南门口、杜甫江阁,又沿着江走了走,从橘子洲大桥上走到橘子洲的hhh,并没有坐地铁去。橘子洲晚上去也是很多人,都是来打卡合影的。

傻傻的游客照 @橘子洲头

后面几天又吃了炊烟,感觉确实比在北京吃的费大厨好吃一点hhh,可能因为我比较爱吃牛肉一点。在 IFS 逛了逛,在超级文和友逛了逛,在湖南大学逛了逛,在岳麓山狼狈地爬了爬(下雨天跟着高德地图爬了一条泥巴路,真的很蠢)。

中间抽出一天时间去了张家界,从观沙岭坐城铁就可以到,感觉湖南的城际铁路修的真不错👍

去了天门山景区,结果山上又是下雨,雾蒙蒙的,不过人很少,我觉得也很有趣hhhh

工作人员教的游客照手势 @天门山

金色印象捏捏全身,抄手、酸辣粉都巨好吃,一定要再去吃!😋

最后想说大连太美啦,特别是从飞机上看,真的好喜欢大连🥰

大连 @飞机

+ \ No newline at end of file diff --git a/dalian.html b/dalian.html index 9698c66..ca47092 100644 --- a/dalian.html +++ b/dalian.html @@ -139,12 +139,13 @@

在大连

+ \ No newline at end of file diff --git a/decision-tree.html b/decision-tree.html index dfd3c2d..74bb1a6 100644 --- a/decision-tree.html +++ b/decision-tree.html @@ -189,12 +189,13 @@

决策树

&=\rho\times\Big(\text{Ent}(\tilde{D})-\sum_{v=1}^V\tilde{r}_v\text{Ent}(\tilde{D}^v)\Big) \end{aligned}

其中

Ent(D~)=k=1Yp~klog2p~k\text{Ent}(\tilde{D})=-\sum_{k=1}^{|\mathcal{Y}|}\tilde{p}_k\log_2 \tilde{p}_k

对于问题2

对于缺失属性值的样本如何将它从父结点划分到子结点中?

多变量决策树

决策树形成的分类边界的明显特点:轴平行,分类边界由若干个与坐标轴平行的分段组成。

优点:学习结果可解释性强,每个划分都对应一个属性取值

不足:决策树对复杂分类使用分段近似,此时的决策树会相当复杂,由于要进行大量的属性测试,预测时间开销会很大。

若能使用斜的划分边界,如图中红色线段所示,则决策树模型将大为简化。“多变量决策树” (multivariate decision tree) 就是能实现这样的“斜划分”甚至更复杂划分的决策树。

总结

+ \ No newline at end of file diff --git a/index.html b/index.html index f134b31..ba3cf9b 100644 --- a/index.html +++ b/index.html @@ -611,12 +611,13 @@

+ \ No newline at end of file diff --git a/linear-algebra-01.html b/linear-algebra-01.html index 5790ef0..b13f07c 100644 --- a/linear-algebra-01.html +++ b/linear-algebra-01.html @@ -206,12 +206,13 @@

[线性代数] 第1章 向量空间

U_3&=\{(0,y,y)\in\mathbf{F}^3:y\in\mathbf{F}\}. \end{aligned}

证明 U1+U2+U3U_1+U_2+U_3 不是直和.

证明 显然 F3=U1+U2+U3\mathbf{F}^3=U_1+U_2+U_3,这是因为每个向量 (x,y,z)F3(x,y,z)\in\mathbf{F}^3 都可以写成

(x,y,z)=(x,y,0)+(0,0,z)+(0,0,0),(x,y,z)=(x,y,0)+(0,0,z)+(0,0,0),

右端第一个向量属于 U1U_1,第二个向量属于 U2U_2,第三个向量属于 U3U_3.

然而 F3\mathbf{F}^3 不是 U1,U2,U3U_1,U_2,U_3 的直和,这是因为向量 (0,0,0)(0,0,0) 能用两种不同方式写成和 u1+u2+u3u_1+u_2+u_3 使得每个 uju_j 属于 UjU_j. 具体来说,我们有

(0,0,0)=(0,1,0)+(0,0,1)+(0,1,1),(0,0,0)=(0,1,0)+(0,0,1)+(0,-1,-1),

当然也有

(0,0,0)=(0,0,0)+(0,0,0)+(0,0,0),(0,0,0)=(0,0,0)+(0,0,0)+(0,0,0),

其中每个等式右端的第一个向量属于 U1U_1,第二个向量属于 U2U_2,第三个向量属于 U3U_3.

1.44 直和的条件

U1,,UmU_1,\dots,U_m 都是 VV 的子空间. “U1++UmU_1+\cdots+U_m 是直和”当且仅当“00 表示成 u1++umu_1+\cdots+u_m(其中每个 ujUju_j\in U_j)的唯一方式是每个 uju_j 都等于 0”.

证明 首先假设 U1++UmU_1+\cdots+U_m 是直和. 那么直和的定义表明:如果 0=u1++um0=u_1+\cdots+u_m(其中每个 ujUju_j\in U_j),则必有每个 uju_j 都等于0.

现在假设:如果 0=u1++um0=u_1+\cdots+u_m(其中每个 ujUju_j\in U_j),则每个 uju_j 都等于0. 为了证明 U1++UmU_1+\cdots+U_m 是直和,设 vU1++Umv\in U_1+\cdots+U_m. 把 vv 写成

v=u1++umv=u_1+\cdots+u_m

其中 u1U1,,umUmu_1\in U_1,\dots,u_m\in U_m. 为证明这个表示法唯一,假设还有一个表示

v=v1++vm,v=v_1+\cdots+v_m,

其中 v1U1,,vmUmv_1\in U_1,\dots,v_m\in U_m. 两式相减,我们有

0=(u1v1)++(umvm).0=(u_1-v_1)+\cdots+(u_m-v_m).

由于 u1v1U1,,umvmUmu_1-v_1\in U_1,\dots,u_m-v_m\in U_m,上式表明每个 ujvju_j-v_j 都等于 0. 于是,u1=v1,,um=vmu_1=v_1,\dots,u_m=v_m.

1.45 两个子空间的直和

UUWW 都是 VV 的子空间,则 U+WU+W 是直和当且仅当 UW={0}U\cap W = \{0\}.

证明 首先假设 U+WU+W 是直和. 若 vUWv\in U\cap W,则 0=v+(v)0=v+(-v),其中 vU,vWv\in U,\, -v\in W. 由于 0 可唯一地表示成 UU 中向量与 VV 中向量的和,我们有 v=0v=0. 于是 UW={0}U\cap W = \{0\},这就证明了定理的一个方面.

另一方面,假设 UW={0}U\cap W=\{0\}. 为证明 U+WU+W 是直和,假设 uU,wW,0=u+wu\in U,\,w\in W,\, 0=u+w. 为完成证明,只需证明 u=w=0u=w=0(由于 1.44). 由上面的等式可得 u=wWu=-w\in W. 于是 uUWu\in U\cap W. 因此 u=0u=0,由此及上面的等式可得 w=0w=0,这就完成了证明.

子空间的和类似于子集的并. 同样,子空间的直和类似于子集的不交并. 任意两个子空间都相交,因为它们都包含 00. 因此要用交为 {0}\{0\} 代替不相交,至少在两个子空间的情形如此.

上面的结果只考虑了两个子空间的情形,在考虑多于两个的子空间的和是否为直和时,只验证任意两个子空间的交为 {0}\{0\} 是不够的. 为了看出这一点,考虑例 1.43,在那个非直和的例子中,我们有 U1U2=U1U3=U2U3={0}U_1\cap U_2=U_1\cap U_3=U_2\cap U_3=\{0\}.

+ \ No newline at end of file diff --git a/linear-algebra-02.html b/linear-algebra-02.html index 46c9b1e..3d96890 100644 --- a/linear-algebra-02.html +++ b/linear-algebra-02.html @@ -159,12 +159,13 @@

[线性代数] 第2章 有限维向量空间

\end{aligned} \right.

无解.

2.5 定义 张成空间(span)

VV 中一组向量 v1,,vmv_1,\dots,v_m 的所有线性组合所构成的集合称为 v1,,vmv_1,\dots,v_m张成空间,记为

span(v1,,vm)\text{span}(v_1,\dots,v_m). 也就是说,

span(v1,,vm)={a1v1++amvm:a1,,amF}.\text{span}(v_1,\dots,v_m)=\{a_1v_1+\cdots+a_mv_m:a_1,\dots,a_m\in\mathbf{F}\}.

空向量组 ()() 的张成空间定义为 {0}\{0\}.

2.6 例 前面的例子表明在 F3\mathbf{F}^3 中,

有些数学家采用术语线性张成空间,意思与张成空间一样.

2.7 张成空间是包含这组向量的最小子空间

VV 中一组向量的张成空间是包含这组向量的最小子空间.

证明v1,,vmv_1,\dots,v_mVV 中的一组向量.

先证明 span(v1,,vm)\text{span}(v_1,\dots,v_m)VV 的子空间. 加法单位元属于 span(v1,,vm)\text{span}(v_1,\dots,v_m),因为

0=0v1++0vm.0=0v_1+\cdots+0v_m.

其次,span(v1,,vm)\text{span}(v_1,\dots,v_m) 在加法下封闭,因为

(a1v1++amvm)+(c1v1++cmvm)=(a1+c1)v1++(am+cm)vm.(a_1v_1+\cdots+a_mv_m)+(c_1v_1+\cdots+c_mv_m)=(a_1+c_1)v_1+\cdots+(a_m+c_m)v_m.

再次,span(v1,,vm)\text{span}(v_1,\dots,v_m) 在标量乘法下封闭,因为

λ(a1v1++amvm)=λa1v1++λamvm.\lambda(a_1v_1+\cdots+a_mv_m)=\lambda a_1v_1+\cdots+\lambda a_mv_m.

于是 span(v1,,vm)\text{span}(v_1,\dots,v_m)VV 的子空间(由于 1.34).

每个 vjv_j 都是 v1,,vmv_1,\dots,v_m 的线性组合(为了证明这一点,在 2.3 中令 aj=1a_j=1 并令其他 aa 都等于 0). 于是 span(v1,,vm)\text{span}(v_1,\dots,v_m) 包含每一个 vjv_j. 反之,由于子空间对加法和标量乘法都封闭,从而 VV 的包含所有 vjv_j 的子空间必定都包含 span(v1,,vm)\text{span}(v_1,\dots,v_m). 因此 span(v1,,vm)\text{span}(v_1,\dots,v_m)VV 的包含所有向量 v1,,vmv_1,\dots,v_m 的最小子空间.

2.8 定义 张成(spans)

span(v1,,vm)\text{span}(v_1,\dots,v_m) 等于 VV,则称 v1,,vmv_1,\dots,v_m 张成 VV.

2.9 例nn 是正整数. 证明

(1,0,,0),(0,1,0,,0),,(0,,0,1)(1,0,\dots,0),(0,1,0,\dots,0),\dots,(0,\dots,0,1)

张成 Fn\mathbf{F}^n. 上面向量组中的第 jj 个向量是第 jj 个元素为 1 其余元素均为 0 的 nn 元组.

证明(x1,,xn)Fn(x_1,\dots,x_n)\in\mathbf{F}^n. 则

(x1,,xn)=x1(1,0,,0)+x2(0,1,0,,0)++xn(0,,0,1).(x_1,\dots,x_n)=x_1(1,0,\dots,0)+x_2(0,1,0,\dots,0)+\cdots+x_n(0,\dots,0,1).

于是 (x1,,xn)span((1,0,,0),(0,1,0,,0),,(0,,0,1))(x_1,\dots,x_n)\in\text{span}\big((1,0,\dots,0),(0,1,0,\dots,0),\dots,(0,\dots,0,1)\big).

2.10 定义 有限维向量空间(finite-dimensional vector space)

如果一个向量空间可以由该空间的某个向量组张成,则称这个向量空间是有限维的.

回想一下,根据定义,每个组都具有有限长度.

上面的例 2.9 表明对任意正整数 nnFn\mathbf{F}^n 是有限维向量空间.

2.11 定义 多项式(polynomial),P(F)\mathcal{P}(\mathbf{F})

在通常的(多项式)加法和标量乘法下,P(F)\mathcal{P}(\mathbf{F})F\mathbf{F} 上的向量空间. 也就是说,P(F)\mathcal{P}(\mathbf{F})FF\mathbf{F}^\mathbf{F}F\mathbf{F}F\mathbf{F} 的全体函数构成的向量空间)的子空间.

一个多项式的系数由该多项式唯一确定. 因此,下面定义的多项式的次数是唯一确定的.

2.12 定义 多项式的次数(degree of a polynomial),degp\text{deg}\,p

在下面的定义中,我们约定 <m-\infin<m,这意味着恒等于 0 的多项式属于 Pm(F)\mathcal{P}_m(\mathbf{F}).

2.13 定义 Pm(F)\mathcal{P}_m(\mathbf{F})

对于非负整数 mm,用 Pm(F)\mathcal{P}_m(\mathbf{F}) 表示系数在 F\mathbf{F} 中且次数不超过 mm 的所有多项式构成的集合.

要验证下面的例子,只需注意到 Pm(F)=span(1,z,,zm)\mathcal{P}_m(\mathbf{F})=\text{span}(1,z,\dots,z^m). 此处我们用 zkz^k 表示函数.

2.14 例 对每个非负整数 mmPm(F)\mathcal{P}_m(\mathbf{F}) 是有限维向量空间.

2.15 定义 无限维向量空间(infinite-dimensional vector space)

一个向量空间如果不是有限维的,则称为无限维的.

2.16 例 证明 P(F)\mathcal{P}(\mathbf{F}) 是无限维的.

证明 考虑 P(F)\mathcal{P}(\mathbf{F}) 中任意一组元素. 记 mm 为这组多项式的最高次数. 则这个组的张成空间中的每个多项式的次数最多为 mm. 因此 zm+1z^{m+1} 不属于这个组的张成空间. 从而没有组能够张成 P(F)\mathcal{P}(\mathbf{F}). 所以 P(F)\mathcal{P}(\mathbf{F}) 是无限维的.

线性无关

v1,,vmVv_1,\dots,v_m\in Vvspan(v1,,vm)v\in\text{span}(v_1,\dots,v_m). 由张成空间的定义,有 a1,,amFa_1,\dots,a_m\in\mathbf{F} 使得

v=a1v1++amvm.v=a_1v_1+\cdots+a_mv_m.

考虑上式中标量选取的唯一性问题. 假设 c1,,cmc_1,\dots,c_m 是另一组标量也使得

v=c1v1++cmvm.v=c_1v_1+\cdots+c_mv_m.

两式相减得

0=(a1c1)v1++(amcm)vm.0=(a_1-c_1)v_1+\cdots+(a_m-c_m)v_m.

于是我们把 00 写成了 v1,,vmv_1,\dots,v_m 的线性组合. 如果 00 只能用显然的方式(每个标量都取零)写成 v1,,vmv_1,\dots,v_m 的线性组合,则每个 ajcja_j-c_j 都等于 0,即每个 aja_j 都等于 cjc_j(因此标量的取法确实是唯一的). 这种情况很重要,所以我们给它起一个特殊的名字——线性无关.

2.17 定义 线性无关(linearly independent)

上一段的推导表明,v1,,vmv_1,\dots,v_m 是线性无关的当且仅当 span(v1,,vm)\text{span}(v_1,\dots,v_m) 中每个向量都可以唯一地表示成 v1,,vmv_1,\dots,v_m 的线性组合.

2.18 例 线性无关组

(a) VV 中一个向量 vv 构成的向量组 vv 是线性无关的当且仅当 v0v\ne0.

(b) VV 中两个向量构成的向量组线性无关当且仅当每个向量都不能写成另一个向量的标量倍.

(c) F4\mathbf{F}^4 中的组 (1,0,0,0),(0,1,0,0),(0,0,1,0)(1,0,0,0),(0,1,0,0),(0,0,1,0) 线性无关.

(d) 对每个非负整数 mmP(F)\mathcal{P}(\mathbf{F}) 中的组 1,z,,zm1,z,\dots,z^m 线性无关.

一个线性无关组中去掉一些向量后,余下的向量构成的向量组仍然线性无关.

2.19 定义 线性相关(linear dependent)

2.20 例 线性相关组

+ \ No newline at end of file diff --git a/mapreduce.html b/mapreduce.html index 0f75e32..a48e301 100644 --- a/mapreduce.html +++ b/mapreduce.html @@ -156,12 +156,13 @@

MapReduce

Emit(AsString(result));

In addition, the user writes code to fill in a mapreduce specification object with the names of the input and output files, and optional tuning parameters. The user then invokes the MapReduce function, passing it the specification object.

2.2 Types

Conceptually the map and reduce functions supplied by the user have associated types:

map     (k1, v1)       -> list(k2, v2)
 reduce  (k2, list(v2)) -> list(v2)

The input keys and values are drawn from a different domain than the output keys and values. The intermediate keys and values are from the same domain as the output keys and values.

2.3 More Examples

3 Implementation

This section describes an implementation targeted to the computing environment: large clusters of commodity PCs connected together with switched Ethernet.

3.1 Execution Overview

The Map invocations are distributed across multiple machines by automatically partitioning the input data into a set of M splits. The input splits can be processed in parallel by different machines.

Reduce invocations are distributed by partitioning the intermediate key space into R pieces using a partitioning function (e.g., hash(key)modRhash(key) \mod R). The number of partitions (R) and the partitioning function are specified by the user.

When the user program calls the MapReduce function, the following sequence of actions occurs:

  1. The MapReduce library in the user program first splits the input files into M pieces of typically 16 megabytes to 64 megabytes (MB) per piece (controllable by the user via an optional parameter). It then starts up many copies of the program on a cluster of machines.
  2. One of the copies of the program is special — the master. The rest are workers that are assigned work by the master. There are M map tasks and R reduce tasks to assign. The master picks idle workers and assigns each one a map task or a reduce task.
  3. A worker who is assigned a map task reads the contents of the corresponding input split. It parses key/value pairs out of the input data and passes each pair to the user-defined Map function. The intermediate key/value pairs produced by the Map function are buffered in memory.
  4. Periodically, the buffered pairs are written to local disk, partitioned into R regions by the partitioning function. The locations of these buffered pairs on the local disk are passed back to the master, who is responsible for forwarding these locations to the reduce workers.
  5. When a reduce worker is notified by the master about these locations, it uses remote procedure calls to read the buffered data from the local disks of the map workers. When a reduce worker has read all intermediate data, it sorts it by the intermediate keys so that all occurrences of the same key are grouped together. The sorting is needed because typically many different keys map to the same reduce task. If the amount of intermediate data is too large to fit in memory, an external sort is used.
  6. The reduce worker iterates over the sorted intermediate data and for each unique intermediate key encountered, it passes the key and the corresponding set of intermediate values to the user’s Reduce function. The output of the Reduce function is appended to a final output file for this reduce partition.
  7. When all map tasks and reduce tasks have been completed, the master wakes up the user program. At this point, the MapReduce call in the user program returns back to the user code.

After successful completion, the output of the mapreduce execution is available in the R output files (one per reduce task, with file names as specified by the user). Typically, users do not need to combine these R output files into one file — they often pass these files as input to another MapReduce call, or use them from another distributed application that is able to deal with input that is partitioned into multiple files.

3.2 Master Data Structures

For each map task and reduce task, the master stores the state (idle, in-progress, or completed), and the identity of the worker machine (for non-idle tasks).

The master is the conduit through which the location of intermediate file regions is propagated from map tasks to reduce tasks. Therefore, for each completed map task, the master stores the locations and sizes of the R intermediate file regions produced by the map task. Updates to this location and size information are received as map tasks are completed. The information is pushed incrementally to workers that have in-progress reduce tasks.

3.3 Fault Tolerance

Worker Failure

The master pings every worker periodically. If no response is received from a worker in a certain amount of time, the master marks the worker as failed.

Completed map tasks are re-executed on a failure because their output is stored on the local disk(s) of the failed machine and is therefore inaccessible. Completed reduce tasks do not need to be re-executed since their output is stored in a global file system.

When a map task is executed first by worker A and then later executed by worker B (because A failed), all workers executing reduce tasks are notified of the re-execution. Any reduce tasks that has not already read the data from worker A will read the data from worker B.

Master Failure

The master writes periodic checkpoints of the master data structures described above. If the master task dies, a new copy can be started from the last checkpointed state.

(However, given that there is only a single master, its failure is unlikely; therefore our current implementation aborts the MapReduce computation if the master fails. Clients can check for this condition and retry the MapReduce operation if they desire.)

Semantics in the Presence of Failures

When the user-supplied map and reduce operators are deterministic functions of their input values, our distributed implementation produces the same output as would have been produced by a non-faulting sequential execution of the entire program.

We rely on atomic commits of map and reduce task outputs to achieve this property.

Each in-progress task writes its output to private temporary files. A reduce task produces one such file, and a map task produces R such files (one per reduce task).

When the map and/or reduce operators are non-deterministic, we provide weaker but still reasonable semantics. In the presence of non-deterministic operators, the output of a particular reduce task R1R_1 is equivalent to the output for R1R_1 produced by a sequential execution of the non-deterministic program. However, the output for a different reduce task R2R_2 may correspond to the output for R2R_2 produced by a different sequential execution of the non-deterministic program.

Consider map task MM and reduce tasks R1R_1 and R2R_2. Let e(Ri)e(R_i) be the execution of RiR_i that committed (there is exactly one such execution). The weaker semantics arise because e(R1)e(R_1) may have read the output produced by one execution of MM and e(R2)e(R_2) may have read the output produced by a different execution of MM.

3.4 Locality

We conserve network bandwidth by taking advantage of the fact that the input data (managed by GFS) is stored on the local disks of the machines that make up our cluster.

GFS divides each file into 64 MB blocks, and stores several copies of each block (typically 3 copies) on different machines. The MapReduce master takes the location information of the input files into account and attempts to schedule a map task on a machine that contains a replica of the corresponding input data. Failing that, it attempts to schedule a map task near a replica of that task’s input data (e.g., on a worker machine that is on the same network switch as the machine containing the data).

3.5 Task Granularity

We subdivide the map phase into M pieces and the reduce phase into R pieces. Ideally, M and R should be much larger than the number of worker machines.

Practical bounds:

The master must take O(M+R)O(M+R) scheduling decisions and keeps O(MR)O(M*R) state in memory.

+ \ No newline at end of file diff --git a/mysql-01.html b/mysql-01.html index 8d375fd..097dbf6 100644 --- a/mysql-01.html +++ b/mysql-01.html @@ -147,12 +147,13 @@

[MySQL 01] SQL查询语句执行流程

ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'

如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。

比如这个例子中的表T中,ID字段没有索引,那么执行器的执行流程是这样的:

  1. 调用InnoDB引擎接口取这个表的第一行,判断ID值是不是10,如果不是则跳过,如果是则将这行存在结果集中;
  2. 调用引擎接口取“下一行”,重复相同的判断逻辑,直到取到这个表的最后一行。
  3. 执行器将上述遍历过程中所有满足条件的行组成的记录集作为结果返回给客户端。

至此,这个语句就执行完成了。

对于有索引的表,执行的逻辑也差不多。第一次调用的是“取满足条件的第一行”这个接口,之后循环取“满足条件的下一行”这个接口,这些接口都是引擎中已经定义好的。

可以在数据库的慢查询日志中看到一个rows_examined的字段,表示这个语句执行过程中扫描了多少行。这个值就是在执行器每次调用引擎获取数据行的时候累加的。

在某些场景下,执行器调用一次,在引擎内部则扫描了多行,因此引擎扫描行数跟rows_examined并不是完全相同的

+ \ No newline at end of file diff --git a/mysql-02.html b/mysql-02.html index 47c114e..9768536 100644 --- a/mysql-02.html +++ b/mysql-02.html @@ -145,12 +145,13 @@

[MySQL 02] SQL更新语句执行流程

但是由于binlog没写完就crash了,这时候binlog里面就没有记录这个语句。因此,之后备份日志的时候,存起来的binlog里面就没有这条语句。 然后就会发现,如果需要用这个binlog来恢复临时库的话,由于这个语句的binlog丢失,这个临时库就会少了这一次更新,恢复出来的这一行c的值就是0,与原库的值不同。
  • 先写binlog后写redo log。如果在binlog写完之后crash,由于redo log还没写,崩溃恢复以后这个事务无效,所以这一行c的值是0。但是binlog里面已经记录了“把c从0改成1”这个日志。所以,在之后用binlog来恢复的时候就多了一个事务出来,恢复出来的这一行c的值就是1,与原库的值不同。
  • 可以看到,如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。

    不只是误操作后需要用这个过程来恢复数据。当需要扩容的时候,也就是需要再多搭建一些备库来增加系统的读能力的时候,现在常见的做法也是用全量备份加上应用binlog来实现的,这个“不一致”就会导致线上出现主从数据库不一致的情况。

    简单说,redo log和binlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。

    小结

    本节介绍了MySQL里面最重要的两个日志,即物理日志redo log和逻辑日志binlog。

    redo log用于保证crash-safe能力。innodb_flush_log_ar_trx_commit这个参数设置成1的时候,表示每次事务的redo log都直接持久化到磁盘。这个参数建议设置成1,这样可以保证MySQL异常重启之后数据不丢失。

    sync_binlog这个参数设置成1的时候,表示每次事务的binlog都持久化到磁盘。这个参数也建议设置成1,这样可以保证MySQL异常重启之后binlog不丢失。

    还介绍了与MySQL日志系统密切相关的“两阶段提交”。两阶段提交是跨系统维持数据逻辑一致性时常用的一个方案,即使不做数据库内核开发,日常开发中也有可能会用到。

    思考题:定期全量备份的周期“取决于系统重要性,有的是一天一备,有的是一周一备”。那么在什么场景下,一天一备会比一周一备更有优势呢?或者说,它影响了数据库系统的哪个指标?

    好处是“最长恢复时间”更短。

    在一天一备的模式里,最坏情况下需要应用一天的binlog。比如,每天0点做一次全量备份,而要恢复出一个到昨天晚上23点的备份。

    一周一备最坏情况就要应用一周的binlog了。

    系统的对应指标就是RTO(恢复目标时间)。

    当然这个是有成本的,因为更频繁全量备份需要消耗更多存储空间,所以这个RTO是成本换来的,就需要根据业务重要性来评估了。

    + \ No newline at end of file diff --git a/mysql-03.html b/mysql-03.html index aba6b30..ca846f1 100644 --- a/mysql-03.html +++ b/mysql-03.html @@ -154,12 +154,13 @@

    [MySQL 03] 事务隔离

    +-----------------------+----------------+

    哪个隔离级别都有它自己的使用场景,要根据自己的业务情况来定。那什么时候需要“可重复读”的场景呢?我们来看一个数据校对逻辑的案例。

    假设你在管理一个个人银行账户表。一个表存了每个月月底的余额,一个表存了账单明细。这时候你要做数据校对,也就是判断上个月的余额和当前余额的差额,是否与本月的账单明细一致。你一定希望在校对过程中,即使有用户发生了一笔新的交易,也不影响你的校对结果。

    这时候使用“可重复读”隔离级别就很方便。事务启动时的视图可以认为是静态的,不受其他事务更新的影响。

    事务隔离的实现

    理解了事务的隔离级别,再来看看事务隔离具体是怎么实现的。这里展开说明“可重复读”。

    在MySQL中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

    假设一个值从1被按顺序改成了2、3、4,在回滚日志里面就会有类似下面的记录。

    当前值是4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的read-view。如图中看到的,在视图A、B、C里面,这一个记录的值分别是1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。对于read-view A,要得到1,就必须将当前值依次执行图中所有的回滚操作得到。

    同时会发现,即使现在有另外一个事务正在将4改成5,这个事务跟read-view A、B、C对应的事务是不会冲突的。

    回滚日志不会一直保留,在不需要的时候才删除。也就是说,系统会判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。

    什么时候才不需要了呢?就是当系统里没有比这个回滚日志更早的read-view的时候。

    基于上面的说明,我们来讨论一下为什么建议尽量不要使用长事务。

    长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。

    在MySQL 5.5及以前的版本,回滚日志是跟数据字典一起放在ibdata文件里的,即使长事务最终提交,回滚段被清理,文件也不会变小。有数据只有20GB,而回滚段有200GB的库。最终只好为了清理回滚段,重建整个库。

    除了对回滚段的影响,长事务还占用锁资源,也可能拖垮整个库。

    事务的启动方式

    如前面所述,长事务有这些潜在风险,建议尽量避免。其实很多时候并不是有意使用长事务,通常是由于误用所致。MySQL的事务启动方式有以下几种:

    1. 显式启动事务语句,beginstart transaction。配套的提交语句是commit,回滚语句是rollback
    2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果只执行一个select语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到主动执行commitrollback语句,或者断开连接。

    有些客户端连接框架会默认连接成功后先执行一个set autocommit=0的命令。这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务。

    因此,建议总是使用set autocommit=1,通过显式语句的方式来启动事务。

    但是有人会纠结“多一次交互”的问题。对于一个需要频繁使用事务的业务,第二种方式每个事务在开始时都不需要主动执行一次“begin”,减少了语句的交互次数。如果有这个顾虑,建议使用commit work and chain语法。

    autocommit为1的情况下,用begin显式启动的事务,如果执行commit则提交事务。如果执行commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行begin语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。

    可以在information_schema库的innodb_trx这个表中查询长事务,比如下面这个语句,用于查找持续时间超过60s的事务。

    select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

    小结

    思考题:有什么方案避免长事务出现或者处理这种情况呢?

    这个问题,我们可以从应用开发端和数据库端来看。

    首先,从应用开发端来看:

    1. 确认是否使用了set autocommit=0。这个确认工作可以在测试环境中开展,把MySQL的general_log开起来,然后随便跑一个业务逻辑,通过general_log的日志来确认。一般框架如果会设置这个值,也就会提供参数来控制行为,你的目标就是把它改成1。
    2. 确认是否有不必要的只读事务。有些框架会习惯不管什么语句先用begin/commit框起来。有些是业务并没有这个需要,但是也把好几个select语句放到了事务中。这种只读事务可以去掉。
    3. 业务连接数据库的时候,根据业务本身的预估,通过SET MAX_EXECUTION_TIME命令,来控制每个语句执行的最长时间,避免单个语句意外执行太长时间。

    其次,从数据库端来看:

    1. 监控information_schema.innodb_trx表,设置长事务阈值,超过就报警或者kill;
    2. Percona的pt-kill工具推荐使用;
    3. 在业务功能测试阶段要求输出所有的general_log,分析日志行为提前发现问题;
    4. 如果使用的是MySQL 5.6或者更新版本,把innodb_undo_tablespaces设置成2(或更大的值)。如果真的出现大事务导致回滚段过大,这样设置后清理起来更方便。

    + \ No newline at end of file diff --git a/mysql-04.html b/mysql-04.html index ecec5fe..6867d32 100644 --- a/mysql-04.html +++ b/mysql-04.html @@ -143,12 +143,13 @@

    [MySQL 04] 索引(上)

    一句话简单来说,索引的出现其实就是为了提高数据查询的效率,就像书的目录一样。

    索引的常见模型

    可以用于提高读写效率的数据结构很多,这里介绍三种常见、也比较简单的数据结构,它们分别是哈希表、有序数组和搜索树。

    哈希表是一种以键-值(key-value)存储数据的结构,我们只要输入待查找的值即key,就可以找到其对应的值即value。哈希的思路很简单,把值放在数组里,用一个哈希函数把key换算成一个确定的位置,然后把value放在数组的这个位置。

    不可避免地,多个key值经过哈希函数的换算,会出现同一个值的情况。处理这种情况的一种方法是,拉出一个链表。

    假设,现在维护着一个身份证信息和姓名的表,需要根据身份证号查找对应的名字,这时对应的哈希索引的示意图如下所示:

    图中,User2和User4根据身份证号算出来的值都是N,但没关系,后面还跟了一个链表。假设,这时候要查ID_card_n2对应的名字是什么,处理步骤就是:首先,将ID_card_n2通过哈希函数算出N;然后,按顺序遍历,找到User2。

    需要注意的是,图中四个ID_card_n的值并不是递增的,这样做的好处是增加新的User时速度会很快,只需要往后追加。但缺点是,因为不是有序的,所以哈希索引做区间查询的速度是很慢的。

    可以设想下,如果现在要找身份证号在[ID_card_X, ID_card_Y]这个区间的所有用户,就必须全部扫描一遍了。

    所以,哈希表这种结构适用于只有等值查询的场景,比如Memcached及其他一些NoSQL引擎。

    有序数组在等值查询和范围查询场景中的性能就都非常优秀。还是上面这个根据身份证号查名字的例子,如果使用有序数组来实现的话,示意图如下所示:

    这里假设身份证号没有重复,这个数组就是按照身份证号递增的顺序保存的。这时候如果要查ID_card_n2对应的名字,用二分法就可以快速得到,这个时间复杂度是O(log(N))。

    同时很显然,这个索引结构支持范围查询。要查身份证号在[ID_card_X, ID_card_Y]这个区间的User,可以先用二分法找到ID_card_X(如果不存在ID_card_X,就找到大于ID_card_X的第一个User),然后向右遍历,直到查到第一个大于ID_card_Y的身份证号,退出循环。

    如果仅仅看查询效率,有序数组就是最好的数据结构了。但是,在需要更新数据的时候就麻烦了,往中间插入一个记录就必须得挪动后面所有的记录,成本太高。

    所以,有序数组索引只适用于静态存储引擎,比如要保存的是2017年某个城市的所有人口信息,这类不会再修改的数据。

    二叉搜索树也是经典数据结构。还是上面根据身份证号查名字的例子,如果用二叉搜索树来实现的话,示意图如下所示:

    二叉搜索树的特点是:每个节点的左儿子小于父节点,父节点又小于右儿子。这样如果要查询ID_card_n2的话,按照图中的搜索顺序就是按照UserA → UserC → UserF → User2这个路径得到。这个时间复杂度是O(log(N))。

    当然为了维持O(log(N))的时间复杂度,就需要保持这棵树是平衡二叉树。为了做这个保证,更新的时间复杂度也是O(log(N))。

    树可以有二叉,也可以有多叉。多叉树就是每个节点有多个儿子,儿子之间的大小保证从左到右递增。二叉树是搜索效率最高的,但是实际上大多数的数据库存储却并不使用二叉树。其原因是,索引不止存在内存中,还要写到磁盘上。

    可以想象一下一棵100万节点的平衡二叉树,树高20。一次查询可能需要访问20个数据块。在机械硬盘时代,从磁盘随机读一个数据块需要10ms左右的寻址时间。也就是说,对于一个100万行的表,如果使用二叉树来存储,单独访问一个行可能需要20个10ms的时间,这个查询非常慢。

    + \ No newline at end of file diff --git a/not-enough-data-01.html b/not-enough-data-01.html index 7e9a4fb..0a888a2 100644 --- a/not-enough-data-01.html +++ b/not-enough-data-01.html @@ -187,12 +187,13 @@

    数据不足下的学习 Part 1:半监督学习

    p(\text{mixup}_\lambda(y\mid\mathbf{x}_i,\mathbf{x}_j))&\approx\lambda p(y\mid\mathbf{x}_i)+(1-\lambda)p(y\mid\mathbf{x}_i) \end{aligned}

    其中 θ\theta^\primeθ\theta 的滑动平均,是 mean teacher。

    图6. Interpolation Consistency Training. MixUp 应用于产生更多带有插值标签的插值样本作为学习目标。

    因为两个随机选择的无标签样本属于不同类别的概率很高(例如在 ImageNet 中有 1000 个物体类),在两个随机无标签样本间应用 mixup 的插值很有可能发生在决策边界附近。根据低密度分离假设,决策边界易于被定位在低密度区域。

    LuICT=Eui,ujUEλBeta(α,α)D[pθ(ymixupλ(ui,uj)),mixupλ(pθ(yui),pθ(yuj))]\mathcal{L}_u^{\text{ICT}}=\mathbb{E}_{\mathbf{u}_i,\mathbf{u}_j∼\mathcal{U}}\mathbb{E}_{\lambda∼\text{Beta}(\alpha,\alpha)}D[p_\theta(y\mid\text{mixup}_\lambda(\mathbf{u}_i,\mathbf{u}_j)),{\text{mixup}}_\lambda(p_{\theta^\prime}(y\mid\mathbf{u}_i),p_{\theta^\prime}(y\mid\mathbf{u}_j))]

    其中 θ\theta^\primeθ\theta 的滑动平均。

    + \ No newline at end of file diff --git a/recommendation-01.html b/recommendation-01.html index 464f39e..d79a6cf 100644 --- a/recommendation-01.html +++ b/recommendation-01.html @@ -294,12 +294,13 @@

    利用逆倾向分数 (IPS) 降低选择偏差

    &=\sum_{(u,i):O_{u,i}=1}\Big(w^TX_{u,i}+\beta_i+\gamma_u\Big)-\sum_{u,i}\log\Big(1+e^{w^TX_{u,i}+\beta_i+\gamma_u}\Big) \end{aligned}

    简化后的整个模型的 log 似然函数为:

    (OX,ϕ)=(i,u):Ou,i=1[wTXu,i+βi+γu]i,ulog[1+ewTXu,i+βi+γu].\ell(O|X,\phi)=\sum_{(i,u):O_{u,i}=1}[w^TX_{u,i}+\beta_i+\gamma_u]-\sum_{i,u}\log\Big[1+e^{w^TX_{u,i}+\beta_i+\gamma_u}\Big].

    对于任意物品 ii 对偏置项 βi\beta_i 的梯度(γu\gamma_u 与之类似):

    βi=uOu,iuPu,i.\frac{\partial\ell}{\partial\beta_i}=\sum_uO_{u,i}-\sum_uP_{u,i.}

    令梯度为 0 可解得结论。

    + \ No newline at end of file diff --git a/svm.html b/svm.html index c3464c3..af9e044 100644 --- a/svm.html +++ b/svm.html @@ -189,12 +189,13 @@

    支持向量机

    \xi_i\ge 0 \end{cases}

    ϕ(x)\phi(x)是无限维,无法求整体优化

    ϕ(x1)\phi(x_1)ϕ(x2)\phi(x_2)两个无限维向量内积核函数(Kenerl Function)

    K(x1,x2)=ϕ(x1)Tϕ(x2)K(x_1,x_2)=\phi(x_1)^\text{T}\phi(x_2)

    只要知道一个核函数,不知道无限维映射ϕ(xi)\phi(x_i)的显式表达,仍然可以求解最优

    为什么可以通过求内积代替显式ϕ\phi——对偶问题

    假设知道了KK,如何求解ϕ(xi)\phi(x_i),让优化问题可求解?

    核函数也是有限制的,KK要满足某种特定条件,才能拆成内积,K(x1,x2)K(x_1,x_2)能写成ϕ(x1)Tϕ(x2)\phi(x_1)^\text{T}\phi(x_2)的充要条件:

    (1)交换性:K(x1,x2)=K(x2,x1)K(x_1,x_2)=K(x_2,x_1)

    (2)半正定性:Ci,xi  ,i=1,,N\forall C_i,x_i\;,i=1,\dots,N,有

    i=1Nj=1NCiCjK(xi,xj)0\sum_{i=1}^N\sum_{j=1}^NC_iC_jK(x_i,x_j)\ge0

    高斯核

    无限维的特征变换ϕ(x)\phi(x)

    K(x,x)=exp((xx)2)K(x,x')=\exp(-(x-x')^2)

    一般形式:K(x,x)=exp(λ(xx)2)  ,λ>0K(x,x')=\exp(-\lambda(x-x')^2)\;,\lambda>0

    对偶问题

    定义

    + \ No newline at end of file diff --git a/tag/Causal Inference.html b/tag/Causal Inference.html index dc04251..1d7250a 100644 --- a/tag/Causal Inference.html +++ b/tag/Causal Inference.html @@ -113,12 +113,13 @@

    #Causal Inference

    + \ No newline at end of file diff --git a/tag/Database.html b/tag/Database.html index 04535fd..9d9091a 100644 --- a/tag/Database.html +++ b/tag/Database.html @@ -233,12 +233,13 @@

    + \ No newline at end of file diff --git a/tag/Distributed.html b/tag/Distributed.html index 7a46154..d6e7ff5 100644 --- a/tag/Distributed.html +++ b/tag/Distributed.html @@ -143,12 +143,13 @@

    + \ No newline at end of file diff --git a/tag/Information Theory.html b/tag/Information Theory.html index d42b543..ccca64e 100644 --- a/tag/Information Theory.html +++ b/tag/Information Theory.html @@ -113,12 +113,13 @@

    #Information Theory

    + \ No newline at end of file diff --git a/tag/Linear Algebra.html b/tag/Linear Algebra.html index 5ba272a..5a70d1b 100644 --- a/tag/Linear Algebra.html +++ b/tag/Linear Algebra.html @@ -181,12 +181,13 @@

    + \ No newline at end of file diff --git a/tag/ML.html b/tag/ML.html index a6c32e7..182e32a 100644 --- a/tag/ML.html +++ b/tag/ML.html @@ -233,12 +233,13 @@

    + \ No newline at end of file diff --git a/tag/Math.html b/tag/Math.html index e4ce8c5..b9fdc45 100644 --- a/tag/Math.html +++ b/tag/Math.html @@ -181,12 +181,13 @@

    + \ No newline at end of file diff --git a/tag/Recommendation.html b/tag/Recommendation.html index 1af3b76..3028b55 100644 --- a/tag/Recommendation.html +++ b/tag/Recommendation.html @@ -143,12 +143,13 @@

    + \ No newline at end of file diff --git a/tag/Robustness.html b/tag/Robustness.html index 65ff015..a369b4e 100644 --- a/tag/Robustness.html +++ b/tag/Robustness.html @@ -143,12 +143,13 @@

    + \ No newline at end of file diff --git "a/tag/\360\237\223\226Note.html" "b/tag/\360\237\223\226Note.html" index ea0049c..73f2a4c 100644 --- "a/tag/\360\237\223\226Note.html" +++ "b/tag/\360\237\223\226Note.html" @@ -511,12 +511,13 @@

    + \ No newline at end of file diff --git "a/tag/\360\237\232\236Memory.html" "b/tag/\360\237\232\236Memory.html" index c6ca67e..f591ee5 100644 --- "a/tag/\360\237\232\236Memory.html" +++ "b/tag/\360\237\232\236Memory.html" @@ -191,12 +191,13 @@

    + \ No newline at end of file