诗盗·肥肉是精神累赘

《#诗盗#·肥肉是精神累赘》:码农低薪城鱼贵,山鸡高瘦厦羊肥。穷不顾身富健美,老来病残高消费。

注解

农民进城写代码,发现农村一斤十几的黄翅,城里卖三四十,实在吃不起……
闽清山里有种高脚鸡,几乎没有肥肉,连皮也没有油脂,但是抓回厦门的农村养,全都养肥了!更何况那些肥羊!大量脂肪都是输送到农村富集起来,吃不完的肥肉拿去喂鸡,鸡都肥了,人再吃肥鸡,循环肥胖。
去城里超市买羊肉,只能吃得起一斤三十的肥羊肉,而在山里,几乎没有肥肉的羊肉一斤才六十,这要在城里估计得上百了,突然分不清哪里的消费高。在城里因为穷,吃不起好的品种,回到山里才能吃得起。
最后不得不得出一个结论:穷人才容易吃胖!这是在浪费生命啊!

诗盗·量子邪稣

《#诗盗#·量子邪稣》:生死无待,诡道莫测,量子邪稣藐神话。

注解

生死无待:叠加态
诡道:诡异的轨道
莫测:海森堡测不准原理

霹雳角色“昊天”的诗号:

一睨仙魔惊叹,一笑天地独尊。六界布武,在予一人,始主藐神话

为什么稣不追星?

高中时,很多同学听磁带,谈论共同的明星,稣听的全是一些没人唱的曲或者相对冷门的歌手唱的,于是乎同学都以为稣不追星……

这个误解好大!其实是稣惊讶地发现小小的一个耳机就可以替代所有歌星,歌星唱功再屌,它也可以播放,稣大胆预测将来 AI 可以代替任何人唱歌,所以稣追的星,其实是——耳机。

后来为了保护听力,改为扬声器了。

为什么穷稣砸锅卖铁也要买个跑步机装逼?

  1. 跑步机可以控制时速,比如用 6KM/h 是比较适合稣的,而野跑则是变速运动,一不小心容易伤到膝盖。

  2. 可以在跑步机旁边放个空气净化器,而野跑容易吸尾气。

  3. 健身房有冷气,跑 40 分钟才有的流汗效果,在家不开空调只要 24 分钟,省时省钱。

  4. 健身房偶尔会有美女来约炮。——这问题很大,因为约炮也轮不到稣,会受刺激,伤心。

《诗盗·骚年游》

《#诗盗#·骚年游》:
算来好景只如斯,惟许有钱支。寻常装逼,等闲递笑,诚意吉祥意。
十年情了音尘断,往事不胜思。一狗惨叫,半脸肥鸡,总是咬人屎。
仕途茫然财路断,全家不够吃。一心补脑,半脸肥猪,总吃卵磷脂。

注解

作者:那男性CEO开

诗盗·槽倾池

《#诗盗#·槽倾池》:聊八卦,甩锅拍马屁,谣言何沉;乱吐槽,随手扔垃圾,牛皮为轻。

注解

改编自霹雳角色“墨倾池”的诗号。

话九宸,挥袖风云尽,江山何沉,
随逸兴,负手乾坤定,苍黄为轻。

人工神经网络训练方法——后向传播

人工神经网络训练方法——随机查找》介绍的随机查找方法,有点盲人摸象,所以继续介绍主流的后向传播(BackPropagation)算法。

填坑

先给随机查找做个优化!上篇中的激活函数统一使用 ReLU,其实这是不好的,输出层可以改为 Sigmoid 或 Tanh:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
inline double ActivationFunction_ReLU(double x) {
return std::max(0.0, x);
}
inline double ActivationFunction_Sigmoid(double x) {
return 1.0 / (1 + exp(-x));
}
inline double ActivationFunction_Tanh(double x) {
return (tanh(x) + 1.0) / 2;
}

double AnnRun(const double x[2], double* w) {
double f = ActivationFunction_ReLU(x[0] * w[0] + x[1] * w[1] - w[2]);
double g = ActivationFunction_ReLU(x[0] * w[3] + x[1] * w[4] - w[5]);
return ActivationFunction_Sigmoid(f * w[6] + g * w[7] - w[8]);
}

原因很简单,我们已经知道 Xor 的结果不是 0 就是 1,用 ReLU 是可能大于 1 的,而 Sigmoid 和 Tanh 不会大于 1。

后向传播

理论学习:《如何直观地解释 back propagation 算法?》

原理:求导

训练时,x 和 y 都是固定的,要求的是 a 和 b,所以问题是:当 y 偏离了 delta_y,求 a 和 b 应该修正多少?

分别对 a 和 b 求偏导,则:

1
2
dy/da = x
dy/db = 1

所以

1
2
delta_a = delta_y / x
delta_b = delta_y

代码不会骗人,来一个简化的例子:

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
// BackPropagation.cpp
//

#include <iostream>

void Train(double& a,
double& b,
double input,
double expect_output,
double learning_rate) {
double delta_y = expect_output - (input * a + b);
if (input != 0) {
a += (delta_y / input) * learning_rate;
}
b += delta_y * learning_rate;
}

int main() {
// 要求的函数是:y = 2 * x + 3
const double input[4] = {0, 1, 2, 3};
const double expect_output[4] = {3, 5, 7, 9};

// 初始化状态是:y = 1 * x + 4
double a = 1.0;
double b = 4.0;

std::cout << "Initial: y = " << a << " * x + " << b << "\n";

// 两轮就搞定了
for (int t = 0; t < 2; ++t) {
for (int i = 0; i < 4; ++i) {
Train(a, b, input[i], expect_output[i], 1);
}
}
std::cout << "Trained: y = " << a << " * x + " << b << "\n";

return 0;
}