名片神经网络

2020-07-01 13:44:37

我最近偶然看到安德鲁·肯斯勒(Andrew Kensler)迷人的名片光线追踪器(Raytracer)。他的代码,只有1337字节,生成了一个完整的光线跟踪图像,包括景深、反射、天空渐变和纹理地板。同样,我开始创建一个可以放在名片背面的完整神经网络。下面的代码就是结果,创建了一个带有泄漏-重新激活的3层完全连接的神经网络,并对其进行训练以生成我的名字的小图像。

#include<;bits/stdc++.h>;tyfinf Float f;tydeff std::Vector<;f>;v;f K=0.01,R=0.01;struct L{int w,h,i;v W,x,z;L(int i,int o){W。Resize(i*o);for(f&;a:w)a=(rand()/(1.1-(1<;<;31)-0.5)/sqrt(i+o+0.。);w=i;h=o;}v F(V X){x=X;v a(H);i=h*w;而(i--)a[i/w]+=W[i]*x[i%w];z=a;对于(f&;i:a)i=K>;i?k:i;return a;}v B(V Y){v X(W);i=w*h;而(i--){f Z=Y[i/w]*(z[i/w]>;0?1:k);X[i%w]+=Z*W[i];W[i]-=R*Z*x[i%w];}return X;}};int main(){Ln[]{L(40,50),L(50,50),L(50,1)};int l,z,k,i=500337;而(i-){z=242%243;k=40;vx(K),y;而(k--)x[k]=sin((k%2?z/27/3.:z%27/5)+6.14*k/20);y=x;对于(l=0;l<;3;l++)y=n[l]。F(Y);v Y{2*(y[0]-(";\x1e\0\0\b\x01\0@H\374\377 B\x12@\x18\x12 G\302\\x10@\x12\372\377\221\x10\0\0\200\0\0\\x02";[z/8]>;>;z%8&;1)。B(Y);putchar(";.,-*Oo##";[(Int)(y[0]*8)%9]);如果(i%27<;1)放入(i?i%243?";";:";\033[9A";:";:\r\-Oisin Carroll-\n\gh:Oisincar web:imois.in";);}}。

您可以通过单击播放按钮在此处查看输出。(我不愿承认这一点,因为它实际上并没有在浏览器中运行代码:p,但是如果您自己运行代码,您将看到相同或相似的输出)。

代码只有878个字符,并且(如前所述)创建和训练一个小型神经网络。我确信有可能让它变得更短,但我很高兴能走到这一步!我想把它再短一点就不可能推理了,现在至少可以很容易地添加或删除新的层,并且向前/向后传播相当整齐!(我发誓我没有偏见)。

定义简单的导入和typedefs。这两个浮点定义用于泄漏REU的泄漏的常数(即\(K\)in\(f(X)=max(Kx,x)\))和学习速率。

层结构L的开始。构造函数接受输入和输出大小,并以Xavier初始化的近似值初始化权重矩阵。理想情况下,随机变量应该是正态分布的,但是线性似乎也可以很好地工作!

Layer结构的两个函数。F执行前向传播,获取输入向量并返回输出。有些值被缓存以备以后使用。B执行反向传播,取输出的导数,更新权重矩阵,并返回输入的导数。两家公司都在使用漏水的RELU。

从Main开始,创建一个3层网络。该网络接受40个值作为输入,具有两个隐含层,每个隐含层有50个节点,最后返回单个值。输入基于当前预测的x,y坐标,输出是该像素应该是空格还是';#';的单个值。在最后,我们打开训练循环,它运行500336次迭代,这是输出大小的倍数;243.

生成输入向量x。x的每个元素都基于当前预测的像素的x或y坐标的sin。

根据网络的输出y,计算\(\frac{de}{dy}\)。我们使用均方误差,所以导数正好是\(2(y-\hat{y})\),其中\(\hat{y}\)是目标值,并编码在字符串中。当用非ASCII字符书写时,这要短得多。

输出:根据预测值的高低选择不同的字符。如果我们位于行尾(I%27==0),或者我们已经完成了一个完整的纪元(I%243==0),则打印特殊字符。最后,当我们完成时,i==0并打印结束文本。

谢谢你的阅读!我想听听关于如何缩短篇幅的建议,或者任何其他的想法。