引言

分析由PyInstaller打包的Python程序是一个常见需求。本文将详细记录我对一个名为xxxx.exe的PyInstaller打包程序进行解包和反编译的全过程。

第一步:识别打包工具

通过观察程序图标和文件特征,确认这是一个由PyInstaller打包的Python脚本。PyInstaller是一个流行的Python打包工具,能将Python脚本转换为独立的可执行文件。

第二步:使用pyinstxtractor解包

我使用了专门针对PyInstaller的解包工具pyinstxtractor

1
python pyinstxtractor.py xxxx.exe

执行后输出如下:

1
2
3
4
5
6
7
8
9
10
[+] Processing xxxx.exe
[+] Pyinstaller version: 2.1+
[+] Python version: 36
[+] Length of package: 5612452 bytes
[+] Found 59 files in CArchive
[+] Beginning extraction...please standby
[+] Possible entry point: pyiboot01_bootstrap.pyc
[+] Possible entry point: xxxx.pyc
[+] Found 133 files in PYZ archive
[+] Successfully extracted pyinstaller archive: xxxx.exe

解包完成后,生成了一个xxxx.exe_extracted目录,其中包含所有解包出的pyc文件和dll文件。

第三步:确定Python版本

要正确反编译pyc文件,必须知道原始Python的确切版本。通过以下方法确认:

(1) 可以直接在目录中看到python311.dll文件,可知是python3.11版本。

(2) 具体是python哪个版本,

我们随便打开一个PYZ-00.pyz_extracted目录下的pyc文件(例如base64.pyc),查看其头部信息,前四个字节为A70D0D0A。

我们可以在python的官方仓库中找到不同版本pyc的magic值: https://github.com/python/cpython/blob/main/Include/internal/pycore_magic_number.h
检索到python3.11这部分:

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
Python 3.11a1 3450 Use exception table for unwinding ("zero cost" exception handling)
Python 3.11a1 3451 (Add CALL_METHOD_KW)
Python 3.11a1 3452 (drop nlocals from marshaled code objects)
Python 3.11a1 3453 (add co_fastlocalnames and co_fastlocalkinds)
Python 3.11a1 3454 (compute cell offsets relative to locals bpo-43693)
Python 3.11a1 3455 (add MAKE_CELL bpo-43693)
Python 3.11a1 3456 (interleave cell args bpo-43693)
Python 3.11a1 3457 (Change localsplus to a bytes object bpo-43693)
Python 3.11a1 3458 (imported objects now don't use LOAD_METHOD/CALL_METHOD)
Python 3.11a1 3459 (PEP 657: add end line numbers and column offsets for instructions)
Python 3.11a1 3460 (Add co_qualname field to PyCodeObject bpo-44530)
Python 3.11a1 3461 (JUMP_ABSOLUTE must jump backwards)
Python 3.11a2 3462 (bpo-44511: remove COPY_DICT_WITHOUT_KEYS, change
MATCH_CLASS and MATCH_KEYS, and add COPY)
Python 3.11a3 3463 (bpo-45711: JUMP_IF_NOT_EXC_MATCH no longer pops the
active exception)
Python 3.11a3 3464 (bpo-45636: Merge numeric BINARY_*INPLACE_* into
BINARY_OP)
Python 3.11a3 3465 (Add COPY_FREE_VARS opcode)
Python 3.11a4 3466 (bpo-45292: PEP-654 except*)
Python 3.11a4 3467 (Change CALL_xxx opcodes)
Python 3.11a4 3468 (Add SEND opcode)
Python 3.11a4 3469 (bpo-45711: remove type, traceback from exc_info)
Python 3.11a4 3470 (bpo-46221: PREP_RERAISE_STAR no longer pushes lasti)
Python 3.11a4 3471 (bpo-46202: remove pop POP_EXCEPT_AND_RERAISE)
Python 3.11a4 3472 (bpo-46009: replace GEN_START with POP_TOP)
Python 3.11a4 3473 (Add POP_JUMP_IF_NOT_NONE/POP_JUMP_IF_NONE opcodes)
Python 3.11a4 3474 (Add RESUME opcode)
Python 3.11a5 3475 (Add RETURN_GENERATOR opcode)
Python 3.11a5 3476 (Add ASYNC_GEN_WRAP opcode)
Python 3.11a5 3477 (Replace DUP_TOP/DUP_TOP_TWO with COPY and
ROT_TWO/ROT_THREE/ROT_FOUR/ROT_N with SWAP)
Python 3.11a5 3478 (New CALL opcodes)
Python 3.11a5 3479 (Add PUSH_NULL opcode)
Python 3.11a5 3480 (New CALL opcodes, second iteration)
Python 3.11a5 3481 (Use inline cache for BINARY_OP)
Python 3.11a5 3482 (Use inline caching for UNPACK_SEQUENCE and LOAD_GLOBAL)
Python 3.11a5 3483 (Use inline caching for COMPARE_OP and BINARY_SUBSCR)
Python 3.11a5 3484 (Use inline caching for LOAD_ATTR, LOAD_METHOD, and
STORE_ATTR)
Python 3.11a5 3485 (Add an oparg to GET_AWAITABLE)
Python 3.11a6 3486 (Use inline caching for PRECALL and CALL)
Python 3.11a6 3487 (Remove the adaptive "oparg counter" mechanism)
Python 3.11a6 3488 (LOAD_GLOBAL can push additional NULL)
Python 3.11a6 3489 (Add JUMP_BACKWARD, remove JUMP_ABSOLUTE)
Python 3.11a6 3490 (remove JUMP_IF_NOT_EXC_MATCH, add CHECK_EXC_MATCH)
Python 3.11a6 3491 (remove JUMP_IF_NOT_EG_MATCH, add CHECK_EG_MATCH,
add JUMP_BACKWARD_NO_INTERRUPT, make JUMP_NO_INTERRUPT virtual)
Python 3.11a7 3492 (make POP_JUMP_IF_NONE/NOT_NONE/TRUE/FALSE relative)
Python 3.11a7 3493 (Make JUMP_IF_TRUE_OR_POP/JUMP_IF_FALSE_OR_POP relative)
Python 3.11a7 3494 (New location info table)
Python 3.11b4 3495 (Set line number of module's RESUME instr to 0 per PEP 626)

Magic Number是4字节的二进制数据,我们找到对应的十进制数据后,通过以下代码得到相应的二进制数据

1
2
3
MAGIC_NUMBER = (3495).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'big')
print(hex(_RAW_MAGIC_NUMBER))

可以得到0xA70D0D0A。从而确定具体的版本为3495也就是3.11b4。

第四步:修复pyc文件头

PyInstaller生成的pyc文件缺少标准pyc文件应有的头部信息,需要手动修复。步骤如下:

我们要逆向的是xxx.pyc文件,但是这一步,我们还不能直接反编译pyc文件,因为pyinstaller删除了pyc文件的头部信息中包含的magic number和时间戳等信息,我们需要先将其转换为可以被反编译器识别的格式。
观察xxxx.pyc头部

1
2
3
4
E3 00 00 00 00 00 00 00 | 00 00 00 00 00 05 00 00
00 00 00 00 00 F3 18 02 | 00 00 97 00 64 00 64 01
6C 00 5A 00 64 00 64 01 | 6C 01 5A 01 64 00 64 01
6C 02 5A 02 64 00 64 01 | 6C 03 5A 03 64 00 64 01

base64.pyc头部

1
2
3
4
A7 0D 0D 0A 00 00 00 00 | 00 00 00 00 E3 00 00 00
00 00 00 00 00 00 00 00 | 05 00 00 00 00 00 00 00
00 F3 A2 02 00 00 97 00 | 64 00 5A 00 64 01 64 02
6C 01 5A 01 64 01 64 02 | 6C 02 5A 02 64 01 64 02

虽然我完全看不出有什么关联。

接下来我们新建一个conda环境,版本号和上面的pyc文件版本一致,写一个hello world的py文件,编译为pyc文件。

1
python -m py_compile hello_world.py

再次观察头部信息

1
2
3
4
A7 0D 0D 0A 00 00 00 00 | 42 3A 64 68 27 01 00 00
E3 00 00 00 00 00 00 00 | 00 00 00 00 00 04 00 00
00 00 00 00 00 F3 A6 00 | 00 00 97 00 64 00 A0 00
00 00 00 00 00 00 00 00 | 00 00 00 00 00 00 00 00

这时可以观察到规律了,”E3 00 00 00 00 00 00 00”这第二行以及”00 00 97 00 64 00 A0 00”第三行

我们将”A7 0D 0D 0A 00 00 00 00 | 42 3A 64 68 27 01 00 00”插入到xxxx.pyc的头部信息中。

第五步:尝试反编译

尝试使用uncompyle6

首先尝试使用uncompyle6进行反编译:

1
uncompyle6 xxxx_patched.pyc

但发现uncompyle6最高仅支持到Python 3.8版本,而我们的文件是3.11版本,无法兼容。

尝试使用pycdc

于是转向另一个反编译工具pycdc:

1
2
3
4
5
6
git clone https://github.com/zrax/pycdc.git
cd pycdc
mkdir build
cmake -S . -B build
cmake --build build
./pycdc.exe xxxx_patched.pyc

但遇到了错误:

1
Error decompyling xxxx_patched.pyc: vector too long

使用pycdas获取字节码

当直接反编译失败时,可以使用pycdc附带的pycdas工具获取字节码表示:

1
./pycdas xxxx_patched.pyc

然后将输出的字节码提交给AI大模型(如DeepSeek)进行人工逆向分析,最终成功还原出原始Python代码。

经验总结

  1. 版本匹配至关重要:PyInstaller解包和pyc反编译都需要精确匹配Python版本
  2. 工具链组合使用:没有单一工具能解决所有问题,需要灵活组合多种工具
  3. 人工分析必不可少:当自动化工具失败时,人工分析字节码是最后的手段

工具推荐

  1. 解包工具:pyinstxtractor
  2. 反编译工具:
  3. 辅助工具:
    • WinHex (用于二进制分析)
    • AI大模型 (用于字节码解释)

如何在Docker中正确配置代理服务器

引言

在使用Docker时,许多用户会遇到需要通过代理服务器访问外部网络资源的情况。本文将详细介绍如何为Docker配置代理服务器,解决常见的代理配置问题,并提供实用的调试技巧。

一、Docker代理配置方法

1. 通过systemd配置(推荐)

这是最可靠的方法,适用于使用systemd管理Docker服务的Linux系统:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建配置目录
sudo mkdir -p /etc/systemd/system/docker.service.d

# 创建代理配置文件
sudo tee /etc/systemd/system/docker.service.d/http-proxy.conf << EOF
[Service]
Environment="HTTP_PROXY=http://127.0.0.1:7890"
Environment="HTTPS_PROXY=http://127.0.0.1:7890"
Environment="NO_PROXY=localhost,127.0.0.1,::1,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16"
EOF

# 重新加载systemd配置并重启Docker
sudo systemctl daemon-reload
sudo systemctl restart docker

2. 通过Docker守护进程配置

编辑/etc/docker/daemon.json文件:

1
2
3
4
5
6
7
8
9
10
11
12
sudo tee /etc/docker/daemon.json << EOF
{
"proxies": {
"http-proxy": "http://127.0.0.1:7890",
"https-proxy": "http://127.0.0.1:7890",
"no-proxy": "localhost,127.0.0.1,::1"
}
}
EOF

# 重启Docker服务
sudo systemctl restart docker

3. 通过Docker客户端配置

编辑~/.docker/config.json文件(如果不存在则创建),写入以下内容:

1
2
3
4
5
6
7
8
9
{
"proxies": {
"default": {
"httpProxy": "http://127.0.1:7890",
"httpsProxy": "http://127.0.1:7890",
"noProxy": "localhost,127.0.1,::1"
}
}
}

不过,该配置仅适用于新容器和构建,不会影响现有容器。

4. 使用 CLI 设置代理

无需配置 Docker 客户端, 在调用时在命令行上指定代理配置 docker build 和 docker run 命令。

命令行上的代理配置使用 –build-arg 标志进行构建,并使用 –env 标志来使用代理运行容器。

1
2
docker build --build-arg HTTP_PROXY="http://127.0.1:7890" .
docker run --env HTTP_PROXY="http://127.0.1:7890" redis

二、验证代理配置

配置完成后,可以通过以下命令验证:

1
2
3
4
5
# 检查代理设置是否生效
docker info | grep -i proxy

# 测试拉取镜像
docker pull hello-world

三、解决常见问题

问题1:代理配置后仍无法连接

症状:配置了代理,但Docker仍然无法拉取镜像,出现”EOF”错误。

解决方案

  1. 确保代理服务器正常运行:
    1
    curl -x http://127.0.0.1:7890 http://example.com
  2. 检查代理类型是否正确(HTTP vs SOCKS)
  3. 临时禁用代理测试:
    1
    2
    3
    sudo mv /etc/systemd/system/docker.service.d/http-proxy.conf /etc/systemd/system/docker.service.d/http-proxy.conf.bak
    sudo systemctl restart docker
    docker pull hello-world

问题2:docker-compose build不使用代理

症状docker pull工作正常,但docker-compose build不使用代理。

可以尝试的解决方案

  1. 修改docker-compose.yml,添加build参数:
    1
    2
    3
    4
    5
    6
    7
    8
    services:
    your-service:
    build:
    context: .
    args:
    HTTP_PROXY: ${HTTP_PROXY}
    HTTPS_PROXY: ${HTTPS_PROXY}
    NO_PROXY: ${NO_PROXY}
  2. 或者在运行命令时显式设置环境变量:
    1
    HTTP_PROXY=http://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 docker-compose build
  3. 关闭BuildKit(不推荐长期方案):
    1
    export DOCKER_BUILDKIT=0

五、总结

通过本文介绍的方法,应该能够解决大多数Docker代理配置问题。

烘焙笔记:海绵蛋糕探索之路

海绵蛋糕配方

经过无数次尝试后,我目前的配方:

8寸模具用量

  • 鸡蛋 4个(约200g)
  • 白糖 120g(建议白砂糖和面粉重量1:1,千万别再减了!减少会导致消泡,实践了一下,白砂糖可以略微多一点点,但不能少)
  • 低筋面粉 120g
  • 牛奶 40g
  • 黄油 20g

6寸模具用量

  • 鸡蛋 2个(约100g)
  • 白糖 60g(千万别再减了!)
  • 低筋面粉 60g
  • 牛奶 20g
  • 黄油 10g

这个比例做出来的蛋糕高度刚好,不会太甜,组织也很细腻。增大和减小蛋糕可以按照比例调整。

制作过程中的小心得

全蛋打发

我习惯先把鸡蛋隔温水加热到40度左右(手摸上去温温的),这样比较好打发。

判断打发到位的两个小技巧:

  1. 用打蛋头画个”8”字,纹路能保持几秒不消失
  2. 插根牙签进去,能立住3秒不倒

面粉搅拌

面粉一定要分三次过筛加入,否则会在内部产生不容易搅拌均匀的面粉疙瘩。采用”翻拌”的手法,就像炒菜那样,从底下往上翻,动作要轻但要快。

黄油牛奶

黄油一定要完全融化,和牛奶充分混合后保持温热

常见问题解决方案

蛋糕长不高

  • 检查糖量是否足够(白砂糖真的不能减!)
  • 确保全蛋打发到位
  • 搅拌时动作要轻柔

内部有大孔洞

  • 入炉前记得震两下模具
  • 面粉要过筛
  • 搅拌要均匀但不过度

口感太干

  • 可以加10g蜂蜜替代部分糖
  • 烘烤时间不要过长
  • 出炉后及时脱模

一些实用小贴士

  1. 模具抹油比垫油纸更方便脱模
  2. 脱模后放凉时最好盖块布,防止表面干硬

DELL T640的风扇噪音问题解决方法

实验室中有一台DELL T640工作站,但在插着一张RTX3080的情况下,风扇噪音大的飞起,和机房里面的服务器一样。
搜索一番说是因为硬件和机器不匹配,导致机器误以为硬件会过热,便把风扇开到最大。

这篇博客将介绍如何通过调整风扇转速来解决T640的噪音问题。

在开始之前,请确保iDrac版本为3.30.30.30,因为新版的iDrac不支持从ipmi手动控制风扇转速。因此该方法需要使用旧版本的iDrac。以下是解决噪音问题的步骤:

步骤 1:开启手动服务器风扇条件

首先,需要通过以下命令开启手动服务器风扇控制:

1
sudo ipmitool -I lanplus -H <IP地址> -U <用户名> -P <密码> raw 0x30 0x30 0x01 0x00

该命令将设置服务器的风扇控制模式为手动模式,这样您就可以手动调整风扇转速。

步骤 2:设置风扇转速

接下来,使用以下命令来设置风扇的转速:

1
sudo ipmitool -I lanplus -H <IP地址> -U <用户名> -P <密码> raw 0x30 0x30 0x02 0xff 0x0a

在上述命令中,0xff代表风扇的索引号,0x0a代表所设置的转速值。
如果设置为最小0x01则机器则会视为风扇损坏,风扇会自动提速到30%左右。
而设置到0x0a则正好视作风扇为健康状态,10%的转速也不再产生噪音。

翻译自:https://neuronaldynamics.epfl.ch/online/Ch1.S2.html

1.2 神经元动力学原理

脉冲对突触后神经元的影响可以用植入细胞内的电极来记录,该电极测量细胞内部与周围环境之间的电势差 $u(t)$ (译注:或称电位差)。这个电势差被称为膜电位。在没有任何输入的情况下,神经元处于静息状态(rest),对应于恒定的膜电位 $u_{rest}$ 。在脉冲到达后,电势发生变化,最后衰减到静息电势,参见图1.5A。如果变化是正的,突触被称作是兴奋性的(excitatory)。如果变化是负的,则突触是抑制性的(inhibitory)。

在静息状态时,细胞膜已经被强烈负极化,膜电位约为-65 mV。兴奋性突触的输入会降低膜的负极化程度,因此称为去极化(depolarization)。如果输入使膜的负极化进一步增加,则称为超极化(hyperpolarization)。

1.2.1 突触后电位

让我们形式化以上观察。我们研究了神经元 $i$ 膜电位随时间的函数 $u_i(t)$ 。在输入脉冲到达之前,我们有 $u_i(t)= u_{rest}$ 。在 $t = 0$ 时,突触前神经元 $j$ 发放脉冲。对于 $t>0$ ,我们在电极上看到神经元 $i$ 的响应如下

$u_i(t)−u_{rest}=:ϵ_{ij}(t). \tag{1.1} \ $

式(1.1)的右侧定义了突触后电位(postsynaptic potential)(PSP)。如果电压差 $u_i(t)-u_{rest}$ 为正(负),则我们具有兴奋性(抑制性)的突触后电位,或简称为EPSP (IPSP)。在图1.5A中,我们绘制了由神经元 $j$ 的脉冲到达神经元 $i$ 的兴奋性突触而引起的EPSP。

图1.5:突触后神经元 $i$ 从两个突触前神经元 $j=1,2$ 接收输入。

A.每个突触前脉冲引发的兴奋性突触后电位(EPSP)都可以用电极测量出电位差$u_i(t)-u_{rest}$ 。由神经元 $j=1$ 的脉冲引起的EPSP随时间的函数为 $ ϵ_{i1}(t−t^{(f)}_1)$ 。

B.来自第二个突触前神经元 $j = 2$ 的脉冲在来自神经元 $j = 1$ 的脉冲之后不久到达,导致第二个突触后电位叠加到了第一个突触后电位上去。

C.一旦 $u_i(t)$ 达到阈值 $\vartheta$ ,就会触发动作电位。可以看到,膜电位开始大幅脉冲状正向偏移(箭头)。在图的纵坐标(也就是电压)上,脉冲的峰值超出范围。脉冲后,电压返回到低于静息电位 $u_{rest}$ 的值。

1.2.2 发放阈值和动作电位

考虑两个突触前神经元 $j=1,2$ ,它们都向突触后神经元 $i$ 发送脉冲信号。神经元 $j=1$ 在 $t_1^{(1)},t_1^{(2)},…$ 时间点处发放脉冲,类似的,神经元 $j=2$ 在 $t_2^{(1)},t_2^{(2)},…$ 时间点处发放脉冲。每个脉冲分别引起突触后电位 $\epsilon_ {i1}$ 或 $\epsilon_ {i2}$ 。只要输入脉冲很少,电位的总变化就大约是各个独立PSP的总和,

$u_i(t)=\sum_j{\sum_f{\epsilon_{ij}(t-t^{(f)}j)+u{rest}}} \tag{1.2}\$

即膜电位对输入脉冲线性响应;参见图1.5B。

另一方面,如果在短时间内输入的脉冲太多,线性度就会下降。膜电位一旦达到临界值 $\vartheta$ ,其轨迹就会显示出与PSP的简单求和完全不同的行为:膜电位表现出幅度约为100 mV的脉冲状偏移。该短电压脉冲将沿着神经元 $i$ 的轴突传播到与其他神经元的突触。对许多类型的神经元而言,在脉冲之后,膜电位不会直接返回到静息电位,而是会经过一个低于静息值的超极化阶段。这种超极化现象称为“脉冲后电位”(spike-after potential)。

单个EPSP的幅度在1 mV范围内。脉冲启动的临界值比静息电位高约20至30 mV。因此,在大多数神经元中,四个脉冲-如图1.5C所示-不足以触发动作电位。取而代之的是,大约20-50个突触前脉冲必须在短时间内到达,以触发突触后动作电位。

$$
u_i(t)=\sum_j{\sum_f{\epsilon_{ij}(t-t_j^{(f)})+u_{rest}}} \tag{1.2}\
$$

翻译自:https://neuronaldynamics.epfl.ch/online/Ch1.S1.html

1.1 神经系统原理

近百年来,生物学研究积累了大量关于大脑结构和功能的详细知识。中枢神经系统中最基本的处理单元是神经元,它们以复杂的模式相互连接。图1.1是这样一个神经元网络的一小部分,图1.1是1900年前后神经科学先驱之一的Ramón y Cajal的画作。我们可以分辨出几个具有三角形或圆形细胞体和长长的线状延伸的神经元。这张图让人一窥大脑皮层中的神经元网络。实际上,大脑皮层的神经元及其连接被挤在一个密集的网络中,每立方毫米有104个以上的细胞体和几公里长的 “线”。在大脑的不同区域,其线的连接模式可能看起来不同。然而,在所有区域,不同大小和形状的神经元构成了基本原件。

图1.1:这幅Ramón y Cajal的画再现了他在显微镜下观察到的哺乳动物皮层中的神经元。只有小部分皮层组织样本中的神经元被染色而清晰可见;实际上,神经元的密度要高得多。细胞B是一个典型的金字塔形细胞,其细胞体呈三角形。树突从侧面向上和细胞分开,可以通过其不规则的外观来识别。轴突则呈现出光滑的细线的形状,向下延伸,有一些分支向左右两边延伸。摘自Ramòn y Cajal(416)。

1.1.1 理想的脉冲神经元

一个典型的神经元可分为三个部分,功能各不相同,分别称为树突(dendrite),胞体(soma)和轴突(axon);见图1.2。

粗略地说,树突起着 “输入装置”的作用,它收集来自其他神经元的信号,并将其传送到胞体。胞体是 “中央处理单元”,执行重要的非线性处理步骤。如果到达胞体的总输入超过一定的阈值,就会产生一个输出信号。输出信号被 “输出装置”-轴突捕获,将信号传递给其他神经元。

图1.2:A. Ramón y Cajal画的单个神经元。图中,可以清楚地区分出树突,胞体和轴突。该插图展示了一个神经元动作电位(示意图)的例子。动作电位是一个1-2毫秒的持续时间和振幅约100 mV的短电压脉冲。

图1.2:B. 信号从突触前神经元 $j$ 传输到突触后神经元 $i$ 。右下端的轴突通向其他神经元。(示意图)

1.1.2 脉冲序列

神经元信号由短电脉冲组成,可以通过在神经元胞体上或靠近神经元的轴突上放置细电极来观察。参见图1.2。

脉冲(pulse),即所谓的动作电位(action potential)或神经脉冲(spike),具有大约100 mV的幅度,通常为1-2 ms的持续时间。随着动作电位沿轴突传播,脉冲的形式不会改变。由单个神经元发出的一系列动作电位称为脉冲序列-一系列有固定模式的事件,以规则或不规则的间隔发生;参见图1.3。由于神经元的每个脉冲看起来都很相似,因此动作电位本身不携带任何信息。重要的是脉冲的数量和时间。动作电位是信号传输的基本单位。

脉冲序列中的动作电位通常会很好地分开。即使输入非常强,也无法在第一个脉冲期间或之后立刻发放第二个脉冲。两个脉冲之间的最小距离定义为神经元的绝对不应期。在绝对不应期之后是相对不应期。在相对不应期阶段中,神经元虽然很难但还是有可能激发动作电位。

1.1.3 突触

突触前神经元的轴突与突触后细胞的树突(或胞体)接触的部位就是突触。脊椎动物大脑中最常见的突触是化学突触(chemical synapse)。在化学突触处,轴突末端非常接近突触后神经元,突触前和突触后细胞膜之间只留下一个微小的间隙。这就是所谓的突触间隙(synaptic cleft)。当一个动作电位到达突触时,会引发一连串复杂的生物化学反应,导致神经递质(neurotransmitter)从突触前端释放到突触间隙中。一旦神经递质分子到达突触后端,就会被突触后细胞膜上的特异性受体检测到,并导致(直接或间接通过生物化学信号链)神经元打开特定的通道,使细胞外液体中的离子流入细胞内。反过来,离子的流入又改变了突触后的膜电位,从而最终将化学信号转化为电反应。突触后神经元对突触前脉冲的电压反应称为突触后电位(postsynaptic potential)。

除化学突触外,神经元还可以通过电突触(electrical synapse)连接,有时称为间隙连接(gap junction)。专门的膜蛋白在两个神经元之间建立直接的电连接。关于间隙连接的功能方面人们知之甚少,但它们通常被认为与神经元的同步有关。

1.1.4 神经元是庞大系统的一部分

神经元分布在由数十亿其他神经元和胶质细胞组成的脑组织网络中。大脑是由不同的区域组成的。大脑皮层可以被认为是由神经元组成的长长的薄片,折叠起来覆盖在其他大脑结构之上。有些皮层区域主要参与处理感觉输入,其他区域参与工作记忆或运动控制等。

对于感觉皮层(sensory cortex)中的神经元,可以在实验中根据它们对哪些刺激表现出强烈反应,来确定其功能。例如,初级视觉皮层中的神经元只对视觉空间的一个小区域内的光点作出反应。神经元对刺激敏感的有限区域被称为神经元的感受野(receptive field)(图1.4)。

视觉皮层中所谓简单细胞的感受野是不均匀的,通常有三个拉长的(译注:即形状被拉长,长条或椭圆形等)子感受野(subfields)中的两个。当一个光点落入其中一个阳性子感受野(positive subfields)时,神经元会更加活跃,即比没有刺激时发出更多的脉冲。而每当光点落入阴性子感受野(negative subfields)时,与展示灰屏时神经元的自发活动相比,它的活动就会减少。事实上,光点并不是最好的刺激。如果一个移动的光条的方向与神经元的阳性子感受野的拉长方向一致,那么神经元的反应会最大限度地提高(231)。

神经科学文献中的很大一部分的工作在于确定感觉皮层中神经元的感受野。视觉皮层(visual cortex)中的神经元响应对应的视觉刺激,而听觉皮层(auditory cortex)或体感皮层(somatosensory cortex)中的神经元响应听觉或触觉刺激。如果人们离开感觉皮层,研究其他皮层,则感受野的概念将变得不太明确。例如,在颞下皮层(inferotemporal cortex),神经元对物体的反应与物体的大小和位置无关。在工作记忆任务中,额叶皮层(frontal cortex)的神经元在根本没有刺激的时候活跃。在本书的第二部分,第三部分和第四部分中,我们介绍了神经元网络的感受野和记忆,其网络作为更大系统的一部分。目前,我们先返回到一个简单的,理想化的神经元。

翻译自:https://neuronaldynamics.epfl.ch/online/Ch1.html

本章的主要目的是介绍神经科学的几个基本概念,特别是动作电位(action potentials)、突触后电位(postsynaptic potentials)、发放阈值(firing thresholds)、不应性(refractoriness)和适应性(adaptation)等概念。基于这些概念,我们建立了一个初步的神经元动力学模型,这个简单的模型(leaky integrate-and-fire model)将作为本书第二和第三部分讨论的广义整合发放模型(generalized integrate-and-fire model)的起点和参考。由于简单模型所使用的数学基本上是一维线性微分方程的数学,所以我们将以这一章为契机,介绍一些将在全书其余部分中使用的数学符号。

由于篇幅所限,我们不能也不想对神经生物学这样一个复杂的领域作全面的介绍。因此,本章中对生物学背景的介绍是有选择的,主要集中介绍本书提到的理论工作的生物学背景。要想深入探讨神经生物学,可以参考本章末尾提到的文献。

在回顾了1.1和1.2节中的神经元特性之后,我们将在1.3节中得到我们的第一个数学神经元模型。最后两节将专门讨论简化模型的优点和局限性。

1.1 神经系统原理

夏寒:Neuronal Dynamics(1.1)-神经系统原理

1.2 神经元动力学原理

夏寒:Neuronal Dynamics(1.2)-神经元动力学原理

本文翻译自-https://neuronaldynamics.epfl.ch/online/index.html

本系列文章的内容翻译自Wulfram Gerstner等人写的《Neuronal Dynamics》

当我们做出决定时,大脑会发生什么?
是什么触发神经元发出信号?
什么是神经编码?
这本面向本科生和初学者的进阶教科书提供了关于计算和理论神经科学领域的全面而最新的介绍。它涵盖了许多经典的主题,包括Hodgkin-Huxley方程和Hopfield模型,以及该领域的最新发展,例如广义线性模型和决策理论。
本书一步步清晰的解释各种概念,非常适合只有微分方程和概率论基础知识的读者。插图和示例丰富。
每节的总结和课堂测试使得本书非常适合用于课程或自学。作者还提供了指向文献和大量参考书目的指南,这对有兴趣进一步研究的读者来说将具有不可估量的价值。

之前看到有个不错的介绍脉冲神经网络的系列文章似乎咕咕咕了。

石在:脉冲神经网络简明教程 第一章:神经元的生物基础

本系列从该文章提到的书《Neuronal Dynamics》出发,以翻译为基础,并添加一些笔记。

此外我也不是该专业的学生。如有错误,望不吝赐教。

第一部分 神经元动力学基础

第一章 简介-神经元与数学

夏寒:Neuronal Dynamics(1)-神经元与数学

第二章 离子通道和Hodgkin-Huxley模型

第三章 树突和突触

第四章 维度约简和相平面分析

第二部分 广义整合发放神经元

第五章 非线性整合发放模型

第六章 适应性和放电模式

第七章 尖峰列和神经编码的变异性

第八章 噪声输入模型:尖峰到达的齐射

第九章 噪声输出:逃逸率和软阈值

第十章 模型估计

第十一章 利用随机神经元模型进行编码和解码

第三部分 神经元网络和群体活动

第十二章 神经元群体

第十三章 连续性方程和福克-普朗克方法

第十四章 积分方程方法

第十五章 快速瞬变和速率模型

第四部分 认知动力学

第十六章 竞争群体和决策制定

第十七章 记忆和吸引子动力学

第十八章 感知的皮层场模型

第十九章 突触可塑性和学习

第二十章 展望:可塑网络中的动力学

参考文献

索引

第一版勘误

啊!Zerotier真是太棒啦

由于校园网屏蔽了所有SMB端口,且同时我的NAS有内网穿透的需求,所以我打算为我的TrueNAS Scale安装上Zerotier。

系统环境变量设置

在安装Zerotier之前我们先需要设置两个系统环境变量,进入系统-高级页面

truenas_zerotier_sys_panel.png

在系统控制面板中添加net.ipv4.ip_forwardnet.ipv4.conf.all.src_valid_mark,设置值为1,也就是true。

truenas_zerotier_sys_env.png

Zerotier安装

接下来安装Zerotier。

由于TrueNAS的Charts已经提供了Zerotier的APP,我们可以直接使用Charts进行安装。
在应用页面中搜索并部署Zerotier:

install_zerotier.png

在网络选项下添加项,并在其中输入你需要加入的网络的id。

install_zerotier_settings.png

Auth Token (API Key)Identity Secret以及Identity Public暂时空着不填。

在下面网络配置这一项中,一定要勾选Host Network,否则zerotier连不上NAS自身开启的服务。
然后点击安装完成安装流程。

启动Zerotier服务,记得要在Zerotier的网站面板上勾选一下NAS的这个IP,同意让NAS加入该网络。

Zerotier网络地址持久化

按照如上步骤安装之后,会发现有一个问题,就是每一次重启服务都会在zerotier的网络中分配一次新的机器ip地址。
这是因为没有设置Identity SecretIdentity Public
接下来完成该步骤。

1、在TrueNAS中,导航到系统设置,然后选择命令行(Shell)选项。

2、在打开的shell窗口中输入以下命令

1
k3s kubectl get namespaces

输出如下:

1
2
3
4
5
6
7
8
NAME              STATUS   AGE
default Active 31d
kube-system Active 31d
kube-public Active 31d
kube-node-lease Active 31d
openebs Active 31d
ix-webdav Active 31d
ix-zerotier Active 51m

3、使用获取到的命名空间运行以下命令:

1
k3s kubectl get -n ix-zerotier pods

输出如下:

1
2
NAME                        READY   STATUS    RESTARTS        AGE
zerotier-59700b7689-gwcqw 0/1 Running 1 (2m30s ago) 7m36s

4、使用命名空间和Pod名称信息,在Pod内部打开一个shell,使用以下命令:

1
k3s kubectl exec -n ix-zerotier --stdin --tty zerotier-59700b7689-gwcqw -- /bin/bash

5、使用以下命令生成Zerotier identity文件:

1
zerotier-idtool generate identity.secret identity.public

6、查看identity.secretidentity.public

1
cat identity.secret
1
cat identity.public

7、记下identity.secretidentity.public的值,接着转到应用程序,选择Zerotier,然后点击编辑。
identity.secretidentity.public分别填入对应的框中,更新配置即可。

然后zerotier会生成一个新的ip地址,并且重新启动Zerotier应用程序或TrueNAS,该地址也不会变化。

0%