手撸神经网络系列之——卷积运算的正向传播(三)
前文介绍了一种卷积运算的骚操作——img2col,但仍不是十分满意,本文将介绍另一种卷积的骚操作——as_strided。
用as_strided结合tensordot函数,实现的卷积运算甚至不需要在Python中做for循环,达到了极致的简洁美。
本系列全部代码见下面仓库:
引用站外地址,不保证站点的可用性和安全性
autograd-with-numpy
GitHub
如有算法或实现方式上的问题,请各位大佬轻喷+指正!
本文很长,希望你忍一下。
一些你需要了解的前置知识Numpy数组在内存中的存储我们首先介绍numpy数组在内存里存储方式。
众所周知,numpy中的数据类型都有其对应的内存占用,例如int64与float64都会占用8个byte的内存空间,bool类型占用1个byte等。具体请移步官方文档进行查看。
除此以外,我们还需要知道numpy数组的元素在内存中的排列顺序。如果 ...
手撸神经网络系列之——卷积运算的正向传播(二)
本文仍然讲解卷积运算的正向传播方法,前一篇文章中我们用for循环将卷积运算实现了一下,重点关注的是卷积的运算过程,而并未对其进行优化,本文将引入一种相对比较容易想到的卷积优化方法——img2col。
本系列全部代码见下面仓库:
引用站外地址,不保证站点的可用性和安全性
autograd-with-numpy
GitHub
如有算法或实现方式上的问题,请各位大佬轻喷+指正!
img2col方法介绍“img2col太简单了,我早就会了!”→直接进入卷积正向传播的第三篇文章。
img2col的目的是将繁杂的卷积过程转化为一次矩阵乘法运算,从而大大降低运算量,为了减少语言上的琐碎描述,下面直接以图片来展示过程,先祭出前面文章里卷积过程的动图:
注意到,卷积核每次在图像上移动时,都会与对应区域做一个内积运算(元素间相乘再求和),这一过程与矩阵乘列向量的过程十分类似,因此就有了以下操作:
上面演示 ...
手撸神经网络系列之——卷积运算的正向传播(一)
在传统图像处理中,卷积占据了非常大的比重,在Transformer出来之前,卷积神经网络(CNN)也长期霸榜CV领域的深度学习任务。
而虽然现在有Transformer等利器,但卷积神经网络仍是众多场景任务中的一把手,尚未有被取代的迹象。
本系列全部代码见下面仓库:
引用站外地址,不保证站点的可用性和安全性
autograd-with-numpy
GitHub
如有算法或实现方式上的问题,请各位大佬轻喷+指正!
为啥要单独讲卷积以下,就是卷积神经网络的示意图:
…不好意思放错了,下面这个才是:
卷积运算因为其不同于其他张量运算的规则以及其重要程度,被我单独拎出来讲,还有一个原因是,卷积虽然不难理解,但其反向传播很容易掉脑细胞。不过,卷积的正反向传播都有一些trick,使用了trick后,算对只是基本操作了,还能让卷积和反向传播的速度非常的快(使用trick后的卷积运算已经和CPU版 ...
手撸神经网络系列之——梯度反传函数具体怎么写?(三)
本文将介绍几种特殊张量运算的反向传播。
众所周知,神经网络中涉及到关于张量的运算不止于加减乘除,还有最大最小值运算等,与常规运算不同,有些特殊运算在数学上甚至是不可微的,但即便如此,我们仍然需要将梯度反传回去。
本系列全部代码见下面仓库:
引用站外地址,不保证站点的可用性和安全性
autograd-with-numpy
GitHub
如有算法或实现方式上的问题,请各位大佬轻喷+指正!
本文将介绍Swapaxes运算、Max运算的反向传播。其他特殊运算,就不再一一列举!(主要太懒了)
Swapaxes与矩阵的转置类似,张量运算swapaxes的目的就是交换某两个轴,其定义为:
def swapaxes(self, axis1, axis2):
...
axis1、axis2即为交换的两个轴的序号。稍微想一想容易知道,怎么换过去的就怎么换回来,反传回去的梯度应该就是把梯度的axis ...
手撸神经网络系列之——梯度反传函数具体怎么写?(二)
上篇文章的文末对广播机制对梯度反向传播的影响做了点讨论,但在张量运算方面仍留了两个坑,本文将努力填掉第一个坑:张量乘法。
本系列全部代码见下面仓库:
引用站外地址,不保证站点的可用性和安全性
autograd-with-numpy
GitHub
如有算法或实现方式上的问题,请各位大佬轻喷+指正!
注意,这里的乘法不再是element-wise Product了,而是“货真价实”的Tensor Multiplication。前文提到过,张量乘法分为以下三种:
一维向量间点乘——Dot
多维张量与一维向量相乘——Mv
多维张量与多维张量相乘——Mm
如此从维数上进行区分是为了方便在反向传播时不容易乱套。
下面先给出正向传播的代码,正向传播非常的无脑:
def __matmul__(self, other):
assert isinstance(other, Tensor), f ...
手撸神经网络系列之——梯度反传函数具体怎么写?(一)
前一篇文章简单介绍了计算图的节点类(Tensor类)的封装方法,在文末给了一个比较直观的反向传播模拟,我们发现,节点将梯度反传至其子节点的过程需要利用其梯度反传函数。
本系列全部代码见下面仓库:
引用站外地址,不保证站点的可用性和安全性
autograd-with-numpy
GitHub
如有算法或实现方式上的问题,请各位大佬轻喷+指正!
为简单起见,在前面文章提到的例子里,所有节点的值均是一个标量,但在神经网络中,大部分节点都应该是矩阵或者更一般的张量形式,对张量运算计算梯度虽然原理类似,但仍会比标量复杂不少。而在代码实现时,其复杂程度的提升不仅仅来自于单变量到多变量的转变,还涉及到张量运算的广播机制。
对于神经网络里可能涉及到的梯度反传函数,我大概将其分为三类:
常见单变量函数的反传
常见矩阵(张量)运算的反传
卷积、池化运算的反传
对于这三类我将从(我所认为的)简单到复杂, ...
手撸神经网络系列之——Tensor类的封装思路
该系列的前一篇文章提到了计算图以及误差在计算图中的传播方式,计算图作为一种图结构,在代码实现上也是比较容易,只需要合理定义图的节点类,再实现一些方法即可,本文将简单讲解一下我自己写的计算图的节点类,语言自然是Python,代码写的比较垃圾,希望高手们多多包涵!
本系列全部代码见下面仓库:
引用站外地址,不保证站点的可用性和安全性
autograd-with-numpy
GitHub
如有算法或实现方式上的问题,请各位大佬轻喷+指正!
从这篇文章开始,我将会陆陆续续贴一些代码,手机端的朋友们对不住了!建议前往电脑端浏览器进行浏览。
初始化作为计算图的节点,如前面提到的,需要包含的基本attribute有以下:
节点的数据
非常容易理解,如前面计算图中提到的$x, y, z$这些数,就是其节点的数据,不过,实际操作中,这些数据都是张量,神经网络中为了并行化提速,一般不会一个数一个数 ...
手撸神经网络系列之——计算图及其构建方式的选择
此文将简单介绍神经网络在编程实现中最重要的概念之一——计算图(Computation Graph)。
其实这部分的内容网上很多博客已经说的很清楚了,那我为什么还要写呢?当然为了凑篇水文!(没看到本站其他文章都是类似于这样的水文吗)除此以外,本文还将介绍计算图的两种常见的构建方式,以及我在自己的神经网络框架中,选择了哪一种作为计算图的实现。
本系列全部代码见下面仓库:
引用站外地址,不保证站点的可用性和安全性
autograd-with-numpy
GitHub
如有算法或实现方式上的问题,请各位大佬轻喷+指正!
在进入正文前,首先请确保你知道训练神经网络的最流行的算法是所谓的“误差逆传播(Error BackPropagation)算法”,我则习惯于称之为“反向传播”,或backward。若你还不知道反向传播,你可能没办法理解计算图是为了干啥。
计算图下面贴一条Google上搜到的对计 ...
手撸神经网络系列之——为什么要手撸NN?(附带一些个人想法)
鄙人本科从数学系毕业后,转入了人工智能领域进行硕士阶段的学习,众所周知,目前该领域最炙手可热的模型便是神经网络(Neural Network),生活中到处都是关于它的例子,例如随处可见的人脸识别系统、使得各国人民间能够愉快交流的翻译软件、手机输入法上的语音转文字系统等,可以说神经网络已经充分渗入到了大众的生活中。
甚至,基于神经网络广泛的应用环境,除了我们这个算是科班的研究领域,其在各种其他的领域也大放异彩,我了解到许多其他专业的同学,都能娴熟地调用各种深度学习库进行一些关于自身领域模型的训练,全民深度学习时代的到来意味着我们科班出身的研究者不能甘心于成为别人口中的调包侠、调参侠,我们在调包、调参的时候有必要去深入了解其背后的细节原理,从而掌握对模型自身结构的认识,在调参的时候更有方向感(bushi,怎么说了半天还是调参侠)可以对神经网络这个暗箱的行为更加熟悉和敏感,从而在自己搭建新的模型时做到事半功倍的效果。
而深入理解神经网络原理的唯一方法,就是自己手撸一个出来。这样达到的效果远比你看数十篇诸如《一分钟看懂神经网络》、《神经网络原理深度剖析》这样的博客要好得多。基于此,如果你正在看 ...
通过SSH隧道端口转发实现内网穿透
前面介绍了一种使用V2ray实现的内网穿透方法,虽然达成了目的,但有诸多不足,例如必须在两台设备上同时运行V2ray,配置文件比较难懂等。尤其是对平时没有科学上网需求(自然也没有科学上网经历)的同学而言,下载V2ray本就是件令人头疼的事。
但事实上,常用的ssh命令也可以用来搞内网穿透,只需要一条命令即可。
现在假设我们面临如下图所示的一种情形:
左侧蓝色框内为家里的局域网,其中包含了一台运行80端口Web服务的服务器Server C,其内网IP为192.168.1.100,通过路由器的NAT地址转换接入Internet。右侧绿色框内为外部的互联网,其中有一台拥有公网IP地址(1.2.3.4)的服务器Server B。另有一台能访问互联网,但未接入左侧局域网的设备Laptop A。现Laptop A想通过连接Server B的8080端口来访问Server C80端口上的Web服务。
可见该情形就是最一般的内网穿透情形,在上面的网络拓扑结构中,既然Server B拥有公网IP,我们可以不过分地假设Server C能通过SSH与Server B建立连接,其中,Server B的SSH ...
大陆iOS系统免拔卡解锁TikTok
郑重声明:本文所介绍内容主要是为了方便学习、娱乐、开拓国际视野。请遵守本国法律法规,切勿在任何地方发布分裂国家,涉恐等违法犯罪的言论。
得益于一些政策,在中国大陆的我们没有办法直接浏览TikTok(抖音海外版),由于TikTok会通过一些方法检测你的电话卡,把大陆的运营商进行屏蔽,因此即便你挂满了梯子,也没有办法浏览TikTok。本文对iOS系统解决这一问题的过程进行了总结,力图让萌新踩更少的坑。
本文参考自下面仓库:
引用站外地址,不保证站点的可用性和安全性
TikTok-Unlock
GitHub
首先,你得有个梯子。
最简单粗暴的方法:直接拔卡,但该方法对于只有一台手机设备,没有平板的穷人而言不太友好,因此下面给出一种不需要拔卡的方法。
此教程所使用的软件为Shadowrocket。
操作过程只需按上面链接,找到关于Shadowrocket的部分,若你使用的是其他软件,可以自己 ...
编写一个自己的QQ机器人
更新于2022/9:由于tx增强了风控,我的QQ机器人无法在服务器上进行登录,不排除后期继续加大风控力度的可能,因此我决定不再折腾QQ机器人,而转战生态更丰富、交互性更好的Telegram Bot。
很早以前用过一段时间酷Q平台开发的机器人客户端,结合自己的逻辑进行各种消息的处理回复,但后来因为某种原因,平台跑路了,因此QQ机器人的开发也搁置了一年左右。这两天又想重新通过一些其他途径把机器人整起来。
本次QQ机器人的搭建过程用到了go-cqhttp项目与nonebot库(作为Python接口),操作系统是64位ARM架构的Linux,当然,需要注册一个QQ小号。
安装go-cqhttp并登录账号从上面的项目中选择适合64位ARM架构Linux系统(请根据自己的操作系统进行选择)的release最新版本,写此文时,最新版为v1.0.0-beta4,将其上传到目标系统,解压,得到三个文件,其中,文件go-cqhttp为可执行文件,为其添加执行权限:
sudo chmod +x go-cqhttp
然后执行:
./go-cqhttp
首次执行该程序,会在当前路径下生成一个配置文件(conf ...
如何在一些常用设备(操作系统)上访问局域网内的Samba服务
前面文章中写到了Samba服务的部署过程,但未提到如何在局域网的其他设备上访问该服务以获取共享的文件,虽然这些东西谷歌一查就有,但我还是想水个文章,对常用操作系统上访问该服务的方法做一个总结。
Windows 10/11在Windows 10/11系统上,不需要装任何其他软件,便可访问局域网的Samba服务。以下以Samba服务器的局域网IP地址为192.168.42.2为例。
临时访问服务,只需打开文件资源管理器,在地址栏中输入\\192.168.42.2,敲个回车,即可看到所有共享的目录,若某些共享目录需要身份认证,则双击进入时会要求账号密码。
若要长期挂载使用,可直接右击“此电脑”,选择“映射网络驱动器”,在界面中输入想要挂载的路径,例如\\192.168.42.2\public
不过此方法需要提前知道共享目录的名称。挂载成功后,可以在文件资源管理器的“网络位置”栏看到挂载的目录:
LinuxLinux系统下同样有很多方法,这里举两个比较简单的方法,其一是直接通过mount命令挂载。
首先在本地创建几个用于挂载的文件夹:
sudo mkdir /mnt/public
sudo ...
在树莓派上部署Samba服务实现局域网文件共享
很早以前买了一块1T的SSD移动硬盘,但找不到啥用处,一直放在家里吃灰,这几天突发奇想,打算把移动硬盘挂载到树莓派上,搞一个局域网文件共享系统,后期可以配合其他设备来实现各种功能。
通过简单的搜索,我了解到一种通信协议称为SMB(Server Message Block),通过一款叫Samba的软件应用到Linux系统上,实现了Linux与Windows文件共享。而且该服务的配置也通俗易懂容易入门,因此我决定在树莓派上整一个。
硬件配置主要是树莓派4B(4G内存很够用),另外当然是一块用于存放文件的存储设备(正常人应该不会想用树莓派系统盘作为存储设备吧)
软件配置树莓派使用了64位Ubuntu 20.04 Server作为运行系统。
处理存储设备这里我先把SSD格式化了一下,目标格式选择了适应性更广的exFAT,其适合用来存储大容量文件,还可以在Mac和Windows等主流操作系统上通用。
将SSD接到树莓派的USB接口上,正常情况下,树莓派可以识别到该SSD的信息。执行以下命令查看SSD的设备名:
sudo fdisk -l
然后将其挂载到一个用于共享文件的目录(我选择的路径是/mn ...
树莓派4B通过USB启动Ubuntu 20.04 Server系统
入手树莓派后,一直以来是用TF卡(micro SD卡)作为存储卡,我购买的TF卡只有32G,TF卡读写速度慢,且容易损坏。
因此我又购入了一块128G,提供USB接口的SSD硬盘,写入了Ubuntu 20.04 Server系统,试图从硬盘把树莓派启动起来。过程中遇坑无数,历经数十次失败后终于成功了,在此总结一下过程。
本文参考自此文章
硬件
树莓派4B(4G内存)
TF卡(SanDisk,32G)
SSD硬盘(STmagic,USB接口,128G)
网线一根(为了通过SSH登录树莓派)
HDMI显示屏(可选,便于实时观察启动过程,查看出现的问题,不过没有也无所谓)
软件
Ubuntu 20.04.2 Server 点此下载
Raspberry Pi OS(官方树莓派系统,也称为Raspbian)点此下载
进入正题修改树莓派的启动配置树莓派默认状态是TF卡启动,需要进行修改,修改需要用到官方树莓派系统,启动流程如下:
将Raspberry Pi OS的img文件烧入TF卡,在boot目录下创建空的ssh文件以在开机后自动开启ssh服务。
将TF卡插入树莓派,连接网线到路由器LA ...
从公网访问内网设备——内网穿透的一种手动部署方法
本文参考自下面文档:
引用站外地址,不保证站点的可用性和安全性
V2Ray反向代理
新V2Ray白话文指南
有时候我们需要远程访问自家家里的局域网设备,比如设备上的NAS服务、Web服务等,这种情况下,如果家里路由器的WAN口被直接分配了公网IP,那么在不考虑安全性的情况下,只要通过端口映射即可轻松达成目的,但一般家用路由器不太可能拿到公网IP,这种方法基本用不起来,这时便可采用另一种方法,称为内网穿透。
内网穿透需要一台具有公网IP的服务器作为中转,一种方法是直接使用成熟的第三方平台,例如花生壳,但免费用户每月只有一个G的流量,如果要付费的话,那倒不如去租一台服务器自己搭,因此我选择了后者。以下假设家里的内网设备为A,公网服务器为B,其IP为1.2.3.4,另一台未接入内网,但需要访问A的设备为C。以下假设需要通过访问1.2.3.4的8080端口来间接访问A设备上的Web服务(80端 ...
利用网关设备搭建私用无污染DNS服务器
前面文章提到过,即使使用了代理,也常会出现无法访问某些网站的情况,其实这就是因为DNS被污染了,因此为了更科学地上网,我们可以在网关设备上搭建一个私用的无污染DNS服务器。
网关设备这里先简单讲一下什么是网关设备,网关设备可以简单理解为你的局域网接入外部网络的最后一道关口(当然实际上不一定是最后一道,比如我下面的例子里 网关外面还有一个路由器),所有局域网流量在进入公网前都将首先经过该设备,再由该设备进行转发。除了普通家用路由器自身即可充当网关设备外,任何一台具备ip转发功能的设备都可以作为网关,比如一台废弃不用的笔记本电脑、部署在设备上的虚拟机等等。
这里我使用的网关设备是树莓派,其相当于一台轻量级的Linux电脑,拥有4逻辑核CPU、4G内存与32G存储卡。
基本网络配置我的网络架构及基本的网络设置大概如下(因为没办法在软件上模拟WiFi,故使用一条以太网线当做LAN-Device与路由器间的WiFi连接):
OpenWrt路由器WAN口连接外网,所有LAN口通过虚拟设备(br-lan)进行桥接,并分配静态IP为192.168.1.1
网关设备树莓派的以太口连接路由器一个LA ...
OpenWrt下游主机通过IPv6上网的一种方法
IPv6因IPv4地址池不够用而被提出,至今已有近30年了,但在国内的普及程度仍非常有限,不过,国内的ISP运营商基本都已经提供IPv6接入了,也就是说家里的宽带一般是支持IPv6的。
很多家用路由器尚无法为局域网设备发放IPv6的全局单播(Global)地址,更有一些号称支持IPv6的路由器,其下游局域网设备只能获取到链路本地(Link-Local)地址,其仅支持同一链路的设备通信(类似于局域网的作用),而不能访问到公网的IPv6。随着IPv6的普及,支持公网IPv6地址分配的路由器今后将会越来越多。
OpenWrt固件支持以Native方式通过WAN口从ISP获取IPv6全局单播地址,虽然支持程度一般,但至少可以通过IPv6上网了。
首先要保证WAN口有IPv6全局单播地址,然后打开/etc/config/network文件,在其中可以看到以下配置:
config interface 'wan6'
option proto 'dhcpv6'
可知IPv6对应的接口是wan6,接下来配置文件/etc/config/dhcp:
config dhcp 'lan'
...
o ...
在OpenWrt上配置透明代理
郑重声明:本文所介绍内容主要是为了方便学习、娱乐、开拓国际视野。请遵守本国法律法规,切勿在任何地方发布分裂国家,涉恐等违法犯罪的言论。
用OpenWrt的原因,我觉得对大部分中国大陆的互联网用户而言是不言而喻的,其拥有比一般路由器更高的灵活性与自由度,更重要的是可以方便舒适地进行某些活动。
这里我们用到的梯子就是v2ray,相信能用上这款软件的,应该或拥有一台VPS并配置好了v2ray服务端,或拥有了能用的机场节点,本文不介绍如何获取节点,只给出在已有节点的条件下,一种能实现透明代理的客户端配置。
配置来自于下面文档:
引用站外地址,不保证站点的可用性和安全性
配置透明代理规则
新V2Ray白话文指南
并经过了一些调整,并删去了一些udp和dns的配置。
为什么要用透明代理?一般而言,v2ray在各操作系统上都有拥有GUI界面的客户端,配置也十分容易,但由于需要下载软件、开启软件、甚 ...
Redmi AC2100路由器刷OpenWrt固件
本文参考自下面视频:
引用站外地址,不保证站点的可用性和安全性
[John] Redmi AC2100 OpenWrt installation (web exploit)
YouTube
首先感谢这位一口流利Chinglish的老哥发的这个视频让我毫无困难地刷机成功。接下来本文将该视频以文字的形式描述一下。
硬件要求如题所示,你需要一台Redmi AC2100路由器,其他openwrt支持的小米系列路由器好像也适用,但本文只针对这一种,以下所有内容仅保证适用于AC2100,其他小米系列可作为参考自己尝试。
如何判断一款路由器是否被openwrt所支持:支持列表
这里我好不容易才找到一款在某东商城和支持列表的交集里的路由器(应该是我的搜索方式不对),也就是这款红米AC2100,某东售价159(不是广告)。
另外,还需要一台能连网线的电脑(openwrt默认关闭WiFi功能,需要通过网线 ...