飞桨分子动力学模拟-论文复现第六期:复现TorchMD

news2024/9/22 13:29:00

飞桨分子动力学模拟-论文复现第六期:复现TorchMD

Paddle for MD 飞桨分子动力学模拟科学计算

复现论文-TorchMD: A deep learning framework for molecular simulations
本项目可在AIStudio一键运行:飞桨分子动力学模拟PaddleMD-复现TorchMD
在这里插入图片描述

【论文复现第六期】相关信息

飞桨第六期论文复现赛128 https://aistudio.baidu.com/aistudio/competition/detail/205/0/task-definition

issue报名地址:https://github.com/PaddlePaddle/Paddle/issues/41482

验收标准:Di-alanine 688 8 min 44 s, Trypsin 3,248 13 min 2 s。(后改为去掉速度要求)

成功后会合入 https://github.com/X4Science

飞桨顶会论文挑战赛第9号 https://www.educoder.net/competitions/index/paddlepaddle-02

torchMD代码学习:https://github.com/torchmd/torchmd

论文地址
论文中文版地址

复现工作

复现工作第一步PaddleMD
第一步完成后运行Tutorial指导手册 复现第二步2PaddleMD提速 复现第三步集成测试

复现相关几个手写API速度测试 经测试,代码中有for循环的,一般速度比没有for循环都要慢30倍左右。

当前复现代码github地址PaddleMd https://github.com/skywalk163/INFINITY/tree/main/examples/PaddleMD

准备论文复现工作

下载论文原作源码

首先git clone下载论文原作的源码,使用命令git clone https://github.com/torchmd/torchmd

相关库安装。

在AIStudio下有些库使用pip无法安装,或者安装好之后不起作用,需要conda或者源码安装。
在AIStudio下如果pip无法安装,基本上我们就只剩下一个选择,就是源码安装。

pip安装moleculukit

使用这条命令pip install "moleculekit<=0.9.14"
如果安装不成功,使用源码安装。

源码安装ParmEd

源码安装ase

ase需要高版本的matplotlib,但是我用pip升级不成功(显示成功,但是版本就是没变)。
后来通过右侧工具条“包管理”,将matplotlib升级到最新版本3.5.1
因为,若安装中报错matplotlib,升级到最新版本,然后再源码安装ase。

pip安装openmm

这个是集成测试的时候使用,若不集成测试,可以不装这个库!
使用命令为:pip install openmm-systems

如果分子结构文件读取的时候报pandas出错,则需要相应降低pandas版本试试。

安装完成后,可以使用import xx的方式,验证是否安装成功。就作者本人的经验来说,运气好的时候,一路顺!运气不好的时候,有些包可能会有反复。

!pip install molkitten pyyaml tqdm pandas networkx scipy parmed ase  # Only needed for minimizers
!pip install pyyaml tqdm pandas networkx scipy parmed ase  # Only needed for minimizers
pip install "moleculekit<=0.9.14"
!cd work && wget https://files.pythonhosted.org/packages/56/75/422fa404b42999d6346545b63542d8c1e30f1cc31e5fc884bb7c9a3995c8/ParmEd-3.4.3.tar.gz 
!cd work && tar -xzvf ParmEd-3.4.3.tar.gz 
!cd work/ParmEd-3.4.3/ && python setup.py install 
# import matplotlib
# matplotlib.__version__
!cd work && wget https://files.pythonhosted.org/packages/69/64/096410b2e0b58aee082b40a37cdd61e708ed722a7471d7cf0e2dcb01cade/ase-3.22.1.tar.gz
!cd work && tar -xzvf ase-3.22.1.tar.gz
!cd work/ase-3.22.1 && python setup.py install 
# 安装之后需要重启内核
!pip install openmm-systems 
import moleculekit
# import ParmEd
import parmed
import ase
import openmm

若不成功,则按照下面安装openmm等,学习于这个项目:h
ttps://aistudio.baidu.com/aistudio/projectdetail/2694076

! mkdir 1
!wget https://repo.anaconda.com/miniconda/Miniconda3-py37_4.8.2-Linux-x86_64.sh
! chmod +x Miniconda3-py37_4.8.2-Linux-x86_64.sh
! bash ./Miniconda3-py37_4.8.2-Linux-x86_64.sh -b -f -p /home/aistudio/1
#! conda install -c rdkit rdkit -y
!yes| /home/aistudio/1/bin/conda install -c conda-forge openmm
!yes |/home/aistudio/1/bin/conda install -c conda-forge pdbfixer
import sys
sys.path.append('/home/aistudio/1/bin/')

import sys
sys.path.append('/home/aistudio/1/lib/python3.7/site-packages/') 

跑通原论文torchmd

先跑通原作代码,对整个流程有个基本了解

开始复现

第一阶段 手工开始单个文件转换

将项目所有核心.py文件,使用%%writefile xx.py的格式,放到notebook cell中,这样可以通过查找替换,快速修改所有的代码。

  • 优点是:代码修改效率高。发现一个问题,解决问题,并可以全部查找、替换,将同类问题全部解决。
  • 缺点是:调试效率较低。需要另开一个notebook文件进行测试,且修改代码后,需要重新执行,甚至要重启测试项目的内核。

代码复现第二阶段

像常规notebook下的调试流程

1、对疑点文件拆分,将函数放到Cell进行测试

测试中可以加入测试代码,验证函数是否正确。最终保证所有函数测试通过

2、测试通过后,将修改写回文件

3、在tutorial.ipynb文件中总测试

优点是,基本不修改tutorial.ipynb文件代码。

代码复现第三阶段

调试精度和速度
速度提高工具
https://www.paddlepaddle.org.cn/documentation/docs/zh/develop/guides/performance_improving/profiling_model.html#profiler
当然最终这个项目里没有使用。

1、速度提高

有些手工写的算子使用了for循环,需要找到并提速。

提升paddleindex_add

5.12日确认了paddleindex_add对速度的影响非常大,这个算子要处理!

其次,在屏蔽掉paddleindex_add后,程序运行速度较快提高,非常利于调试!
目前的思路,是找到黑客马拉松项目里面的index_add代码,然后自己动手写成单独的算子。

6.1日,官方提供put_along_axis算子,可以实现index_add功能!

6.2日,好像put_along算子只支持1D index,以后不能用,后来发现可以使用。

6.4日 使用put_alone_axis函数重写了paddleindex_add,速度提升非常多!基本上跟以前测试的时候使用透传的的速度相当!

质疑numpy()函数

使用了太多的numpy()转换函数,这会大大降低速度。要看看这些转换的原因是什么,能否去掉。

提高paddleindexjia

修改paddleindexjia函数,将其修改成由numpy实现:

#             pos[:, self.nongrouped] -= offset.unsqueeze(1)
#             pos = paddleindexjia(pos, -offset, self.nongrouped)
            pos = pos.numpy()
            offset = offset.unsqueeze(1).numpy()
            pos[:, group] -= offset # 尝试使用numpy来处理 相关语句共4句
            pos = paddle.to_tensor(pos)

最终这一大段应该还有提升空间

        if len(self.nongrouped):
            offset = paddle.floor(pos[:, self.nongrouped] / box) * box
#             pos[:, self.nongrouped] -= offset.unsqueeze(1)
#             pos = paddleindexjia(pos, -offset, self.nongrouped)
            pos = pos.numpy()
            offset = offset.unsqueeze(1).numpy()
            pos[:, group] -= offset # 尝试使用numpy来处理 相关语句共4句
            pos = paddle.to_tensor(pos)
性能分析cProfile

import cProfile
import re
cProfile.run(‘re.compile(“foo|bar”)’)

def my_on_trace_ready(prof): # 定义回调函数,性能分析器结束采集数据时会被调用
  callback = profiler.export_chrome_tracing('./profiler_demo') # 创建导出性能数据到profiler_demo文件夹的回调函数
  callback(prof)  # 执行该导出函数
  prof.summary(sorted_by=profiler.SortedKeys.GPUTotal) # 打印表单,按GPUTotal排序表单项

p = profiler.Profiler(scheduler = [3,14], on_trace_ready=my_on_trace_ready, timer_only=True) # 初始化Profiler对象

p.start() # 性能分析器进入第0个step
测试paddle.profiler

paddle.profiler是飞桨自带的性能分析套件。
但是我在启智平台使用的时候,内核直接重启。
后来发现是最后使用了exit()指令的缘故。

但是分析套件需要数据集部分,没有就报错。曾设想加上一个空的数据集指令来骗过去,但最终没有动手做。

2、精度测试

每个文件分别写调试命令,验证精度。

这个并没有做

对tutorial.ipynb文件中的变量输出,跟torchmd的比对。
print(Epot)
print(system.forces)

在使用同一随机种子的情况,paddlemd和torchmd精度对齐。

集成测试

跟openmm的力场能量进行比较,差别不大,在可接受范围

Running test: test-data/benzamidine/
  angle Energy diff: 1.599e-06 Force diff: 6.954e-05
  bond Energy diff: -2.731e-06 Force diff: 1.177e-04
  dihedral Energy diff: -1.608e-06 Force diff: 7.054e-06
  lennardjones Energy diff: 6.798e-06 Force diff: 1.794e-05
  electrostatic Energy diff: -6.766e-07 Force diff: 1.272e-07
All forces. Total energy: 20.914 Energy diff: 3.382e-06 Force diff 1.458e-04

成功复现

复现成功后,即可进行飞桨分子动力学模拟

使用PaddleMD进行分子动力学模拟

参考PaddleMD指引手册,以前丙氨酸二肽为例,进行分子动力学模拟。1000step大约需要4分钟。

首先编译安装PaddleMD

若有报错缺库,缺啥装啥。

编译安装后,需要重启一下环境。

!cd ~/INFINITY/examples/PaddleMD/ && python setup.py develop 

参考指引手册,进行前丙氨酸二肽分子模拟

INFINITY/examples/PaddleMD/test-data/目录中有各种分子结构文件,比如二面角、水分子、苯甲脒、凝血酶配体等。这里以前丙氨酸二肽为例。

读取前丙氨酸二肽分子结构文件

使用“moleculekit”库读取输入拓扑和起始坐标

from moleculekit.molecule import Molecule
import os
import paddle

testdir = "INFINITY/examples/PaddleMD/test-data/prod_alanine_dipeptide_amber/"
mol = Molecule(os.path.join(testdir, "structure.prmtop"))  # Reading the system topology
mol.read(os.path.join(testdir, "input.coor"))  # Reading the initial simulation coordinates
mol.read(os.path.join(testdir, "input.xsc"))  # Reading the box dimensions

from paddlemd.forcefields.forcefield import ForceField
from paddlemd.parameters import Parameters


precision = paddle.float32
# 加载forcefield力场文件,并使用上述拓扑提取将用于模拟的相关参数
ff = ForceField.create(mol, os.path.join(testdir, "structure.prmtop"))
parameters = Parameters(ff, mol, precision=precision)


创建系统

我们可以创建一个“System”系统对象,该对象将包含模拟期间系统的状态,包括:
1、当前原子坐标
1.当前的盒子大小
1、当前原子速度
1、当前原子力场

from paddlemd.integrator import maxwell_boltzmann
from paddlemd.systems import System

system = System(mol.numAtoms, nreplicas=1, precision=precision)
system.set_positions(mol.coords)
system.set_box(mol.box)
system.set_velocities(maxwell_boltzmann(parameters.masses, T=300, replicas=1))
from paddlemd.forces import Forces
bonded = ["bonds", "angles", "dihedrals", "impropers", "1-4"]
# bonded = ["dihedrals"]
# forces = Forces(parameters, cutoff=9, rfa=True, switch_dist=7.5)
forces = Forces(parameters, cutoff=9, rfa=True, switch_dist=7.5, terms=bonded)
# Evaluate current energy and forces. Forces are modified in-place
Epot = forces.compute(system.pos, system.box, system.forces, returnDetails=True)

print(Epot)
print(system.forces)

动力学积分器

为了执行动力学,我们将创建一个“积分器”对象,用于集成模拟的时间步,以及一个“包装器”对象,用于包装周期单元内的系统坐标

from paddlemd.integrator import Integrator
from paddlemd.wrapper import Wrapper

langevin_temperature = 300  # K
langevin_gamma = 0.1
timestep = 1  # fs

integrator = Integrator(system, forces, timestep, gamma=langevin_gamma, T=langevin_temperature)
wrapper = Wrapper(mol.numAtoms, mol.bonds if len(mol.bonds) else None)

from paddlemd.minimizers import minimize_bfgs

minimize_bfgs(system, forces, steps=500)  # Minimize the system steps=500
from paddlemd.utils import LogWriter

logger = LogWriter(path="logs/", keys=('iter','ns','epot','ekin','etot','T'), name='monitor.csv')

开始集成模拟

from tqdm import tqdm 
import numpy as np

FS2NS = 1E-6 # Femtosecond to nanosecond conversion

steps = 1000 # 1000 
output_period = 10
save_period = 100
traj = []

trajectoryout = "mytrajectory.npy"

iterator = tqdm(range(1, int(steps / output_period) + 1))
# print(f"iterator={iterator}")
Epot = forces.compute(system.pos, system.box, system.forces)
for i in iterator:
    Ekin, Epot, T = integrator.step(niter=output_period)
    wrapper.wrap(system.pos, system.box)
#     currpos = system.pos.detach().cpu().numpy().copy()
#     currpos = system.pos.detach()
    currpos = system.pos
#     print(currpos.shape)
    traj.append(currpos)
#     print(len(traj) )
#     print(f"iterator={iterator}")
    
    if (i*output_period) % save_period  == 0:
        np.save(trajectoryout, np.stack(traj, axis=2))

    logger.write_row({'iter':i*output_period,'ns':FS2NS*i*output_period*timestep,'epot':Epot,'ekin':Ekin,'etot':Epot+Ekin,'T':T})

集成测试

INFINITY/examples/PaddleMD/3集成测试.ipynb/集成测试.ipynb 为集成测试文件,在AIStudio中,到相应位置点开该文件即可。也可以在终端使用命令执行。

集成测试的步骤:

首先使用python setup.py develop安装paddlemd开发模式。

在实际使用中,可以使用普通模式,命令为:python setup.py install

执行测试命令

可以使用python tests/test_paddlemd.py进行集成测试,使用./bin/paddlemd --conf tests/water/water_conf.yaml测试水分子,使用./bin/paddlemd --conf tests/prod_alanine_dipeptide_amber/conf.yaml测试prod alanine dipeptide前丙氨酸二肽,使用./bin/paddlemd --conf tests/trypsin/conf.yaml测试Trypsin胰蛋白酶。

3集成测试.ipynb文件中,上述命令已经放入,直接运行即可。也可以到相应目录,在控制台直接使用相应命令执行。

目前这三个单项测试都可以正常运行不报错。速度大约是torchmd的十六分之一。还有较大提升空间。

集成测试,可以测试一部分,可看到势能和力场等数值跟openmm的较接近。但是后面还是会报错,大约是训练求导那块还有问题。

复现过程中的一些工作留档

手动适配的飞桨API

有些API飞桨没有适配,先手写顶上。

def paddlerandn_like(x) : # 添加飞桨的randn_like函数
    return paddle.randn(x.shape)

# 后来发现飞桨2.3版本已经有了atan2函数,直接用即可
def paddleatan2(input, other): # 飞桨的atan2函数
    atan = paddle.atan(input/other)
    atan[1] = atan[1] + pi
    atan[2] = atan[2] + pi
    return atan

def paddlescatter(x, dim, index, src): # scatter支持1D版本
    
    updates = src
    if len(index.shape) == 1 :
#         for i in index:
#             x[i] += updates[i]
        for i in range(index.shape[0]):
            x[index[i]] += updates[i]
        return x
                                
    i, j = index.shape
    grid_x , grid_y = paddle.meshgrid(paddle.arange(i), paddle.arange(j))
    if dim == 0 :
        index = paddle.stack([index.flatten(), grid_y.flatten()], axis=1)
    elif dim == 1:
        index = paddle.stack([grid_x.flatten(), index.flatten()], axis=1)
        
    # PaddlePaddle updates 的 shape 大小必须与 index 对应
    updates_index = paddle.stack([grid_x.flatten(), grid_y.flatten()], axis=1)
    updates = paddle.gather_nd(updates, index=updates_index)
    return paddle.scatter_nd_add(x, index, updates)

# 这个要使用飞桨黑客松的代码,对速度影响非常大
def paddleindex_add(x, dim, index, source): # 飞桨的index_add
    for i in range(len(index)):
        x[index[i]] += source[i]
    return x

# 最终没有等到黑客松的index_add算子,自己用put_alone_axis写了一个
# 飞桨的put_alone_axis不支持shape不一致的情况,即indices和value比arr长或者短的情况。
# 需要做的,就是要把短的补齐,长的分段传入。
def paddleput_alone_axis(arr, indices, value, axis, reduce="add"):
    #     print(f"==arr.shape:{arr.shape} indices.shape:{indices.shape} value.shape:{value.shape}")
    lenarr = arr.shape[0]
    lenindices = indices.shape[0]
    while lenarr < lenindices:
        arr = paddle.put_along_axis(
            arr, indices[:lenarr].reshape([-1, 1]), value[:lenarr], axis, reduce=reduce
        )
        indices = indices[lenarr:]
        value = value[lenarr:]
        lenarr = arr.shape[0]
        lenindices = indices.shape[0]
    xs = lenarr - lenindices
    if xs >= 1:
        newindices = paddle.concat(
            [indices, paddle.zeros([xs], dtype=paddle.int64)]
        ).reshape([-1, 1])
        newvalue = paddle.concat([value, paddle.zeros([xs, value.shape[-1]])])
    else:
        newindices = indices.reshape([-1, 1])
        newvalue = value
    out = paddle.put_along_axis(arr, newindices, newvalue, axis, reduce=reduce)
    return out


# 为了跟程序里的参数序列对齐,尽量不修改代码,写paddleindex_add
def paddleindex_add(x, dim, index, source):
    return paddleput_alone_axis(x, index, source, dim)

# paddleeye这个不用了,全部用变量乘以paddle.eye(3)实现,解决shape首位>1的情况。
#         box = paddleeye(box, 3)
        box = box*paddle.eye(3) # 可以很好的处理box[2, 3, 3]类型数据
        box = box.sum(1)

def paddleeye(x, n): # 针对[1, 3, 3]输入的特供eye函数
    tmp =x[0][paddle.eye(n).astype(paddle.bool)]
    return tmp.unsqueeze_(0)

# paddleindexjia,使用专为numpy计算的方式,速度比paddleindexjia提高30%以上
#             pos[:, self.nongrouped] -= offset.unsqueeze(1)
#             pos = paddleindexjia(pos, -offset, self.nongrouped)
            pos = pos.numpy()
            offset = offset.unsqueeze(1).numpy()
            pos[:, group] -= offset # 尝试使用numpy来处理 相关语句共4句
            pos = paddle.to_tensor(pos)

def paddleindexjia (x, y, xindex): # 索引/切片/赋值特供版本
    '''
    切片+索引,使用循环来解决切片问题,然后使用中间变量,来实现按照索引赋值
    支持类似的语句pos[:, group] -= offset.unsqueeze(1)
    '''
    xlen = len(x)
    assert len(x.shape) == 3 , "维度不一致,必须为3D数据"
#     if len(y.shape) == 3 and y.shape[0] ==1 :
#         y = paddle.squeeze(y)
    assert len(y.shape) ==2 , "维度不一致,必须为2D数据"
    for i in range(xlen):
        tmp = x[i]
        tmp[xindex] += y
        x[i] = tmp
    return x

# 写飞桨版本的笛卡尔直积函数cartesian_prod
from itertools import product
def paddlecartesian_prod(x,y): # 飞桨版本的笛卡尔直积函数
    z = list(product(x,y))
    z = paddle.to_tensor(z)
    return z.squeeze(axis=-1)
    
# 最终版本笛卡尔直积函数支持变长变量输入
from itertools import product
def paddlecartesian_prod(*x): # 飞桨版本的笛卡尔直积函数
    z = list(product(*x))
    z = paddle.to_tensor(z)
    return z.squeeze(axis=-1)

学习paddlemd里面的几句话

# 这句什么意思        self.require_distances = any(f in self.nonbonded for f in self.energies)
# 也就是力场里面有任何一个nobonded值,则self.require_distances为True,也就是有”长距力“ ?
bonded = ["bonds", "angles", "dihedrals", "impropers", "1-4"]
nonbonded = ["electrostatics", "lj", "repulsion", "repulsioncg"]
terms = bonded + nonbonded

class TestClass():
    bonded = ["bonds", "angles", "dihedrals", "impropers", "1-4"]
    nonbonded = ["electrostatics", "lj", "repulsion", "repulsioncg"]
    terms = bonded + nonbonded
    def __init__(self, terms=None):
        self.energies = [ene.lower() for ene in terms]
        self.require_distances = any(f in self.nonbonded for f in self.energies)
        print(f"self.require_distances:{self.require_distances}")
tmp = TestClass(terms=terms)

提速思考

像类似这样,应该都可以用张量直接操作

for i in range(nsystems):
    if explicit_forces:
        forces[i] = paddleindex_add(forces[i], 0, self.par.angles[:, 0], angle_forces[0])
        forces[i] = paddleindex_add(forces[i], 0, self.par.angles[:, 1], angle_forces[1])
        forces[i] = paddleindex_add(forces[i], 0, self.par.angles[:, 2], angle_forces[2])

调试与总结

复现心得

刚开始选这个复现题目的时候,我承认我大意了,分子动力学模拟这个跟平时接触的机器学习和神经网络有较大的不同,而且有几个算子不支持,导致复现工作几度陷入困境。

在低谷期,只好自己鼓励自己:如果我碰到坎,别人也会碰到;如果我想放弃,那别人也会想放弃。坚持,才能胜利!最终跌跌撞撞,在自己写了几个算子(只求功能,不求速度)之后,程序终于能跑通了!

除了自我鼓励之外,问题拆分也是一个非常有效的解决问题的法宝。几乎所有问题,都可以拆分为小问题,进而拆分为更小更易于解决的问题,最终完成开始看起来几乎不可能完成的任务!

一些技术问题存档

大部分碰到的技术问题,都存档了。比如一些分子库pip无法安装的问题,一些算子的问题等。可以在复现三步走对应的文档下部,看到问题存档。

当前遗留的一些问题

1 集成测试无法完全通过。

2 AI自动求导优化那块可能还有问题。

3 运行速度大约是torchmd的十六分之一,还有很大提升空间。

其中有几个算子需要飞桨官方开发出来。另外整个项目的计算(代码表达式)可能还有较大的改进空间。

引用Citation

Please cite:

@misc{doerr2020torchmd,
      title={TorchMD: A deep learning framework for molecular simulations}, 
      author={Stefan Doerr and Maciej Majewsk and Adrià Pérez and Andreas Krämer and Cecilia Clementi and Frank Noe and Toni Giorgino and Gianni De Fabritiis},
      year={2020},
      eprint={2012.12106},
      archivePrefix={arXiv},
      primaryClass={physics.chem-ph}
}

To reproduce the paper go to the tutorial notebook https://github.com/torchmd/torchmd-cg/blob/master/tutorial/Chignolin_Coarse-Grained_Tutorial.ipynb

结束语

用飞桨,划时代!让我们荡起双桨,在AI的海洋乘风破浪!

飞桨官网:https://www.paddlepaddle.org.cn

因为水平有限,难免有不足之处,还请大家多多帮助。

作者: 网名skywalk 或 天马行空,济宁市极快软件科技有限公司的AI架构师,百度飞桨PPDE。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1381290.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

浅析三种Anaconda虚拟环境创建方式和第三方包的安装

目录 引言 一、Anaconda虚拟环境创建方式 1. 使用conda命令创建虚拟环境 2. 使用conda-forge创建虚拟环境 3. 使用Miniconda创建虚拟环境 二、第三方包的安装和管理 1. 使用 pip 安装包&#xff1a; 2. 使用 conda 安装包&#xff1a; 三、结论与建议 引言 在当今的数…

Ceph入门到精通-通过 CloudBerry Explorer 管理对象bucket

简介 CloudBerry Explorer 是一款可用于管理对象存储&#xff08;Cloud Object Storage&#xff0c;COS&#xff09;的客户端工具。通过 CloudBerry Explorer 可实现将 COS 挂载在 Windows 等操作系统上&#xff0c;方便用户访问、移动和管理 COS 文件。 支持系统 支持 Wind…

【ceph】在虚拟环境中需要给osd所在的虚拟盘扩容操作

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

力扣每日一练(24-1-13)

如果用列表生成式&#xff0c;可以满足输出的型式&#xff0c;但是不满足题意&#xff1a; nums[:] [i for i in nums if i ! val]return len(nums) 题意要求是&#xff1a; 你需要原地修改数组&#xff0c;并且只使用O(1)的额外空间。这意味着我们不能创建新的列表&#xff…

2024年 13款 Linux 最强视频播放器

Linux视频播放器选择多样&#xff0c;如榛名、MPlayer、VLC等&#xff0c;功能强大、支持多格式&#xff0c;满足各类用户需求 Linux有许多非常强大的播放器&#xff0c;与windows最强视频播放器相比&#xff0c;几乎丝毫不逊色&#xff01; 一、榛名视频播放器 榛名视频播放…

Java副本的概念

在Java中&#xff0c;"副本"&#xff08;copy&#xff09;一词可以用于描述不同的概念&#xff0c;具体取决于上下文。以下是两个常见的用法&#xff1a; 对象的副本&#xff1a;在Java中&#xff0c;当你创建一个对象并将其赋值给另一个变量时&#xff0c;实际上是创…

遥感影像-语义分割数据集:高分卫星-云数据集详细介绍及训练样本处理流程

原始数据集详情 简介&#xff1a;该云数据集包括RGB三通道的高分辨率图像&#xff0c;包含高分一、高分二及宽幅数据集。 KeyValue卫星类型高分系列覆盖区域未知场景未知分辨率1m、2m、8m数量12000单张尺寸1024*1024原始影像位深8位标签图片位深8位原始影像通道数三通道标签图…

Nightingale 夜莺监控系统 - 部署篇(1)

Author&#xff1a;rab 官方文档&#xff1a;https://flashcat.cloud/docs 目录 一、概述二、架构2.1 中心机房架构2.2 边缘下沉式混杂架构 三、环境四、部署4.1 中心机房架构部署4.1.1 MySQL4.1.2 Redis4.1.3 Prometheus4.1.4 n9e4.1.5 Categraf4.1.6 验证4.1.7 配置数据源 4…

突然又对 Go 感兴趣,GOPATH entry cannot start with shell metacharacter 错误

打发无聊时间&#xff0c;水文一篇&#xff5e; 事情是这样的&#xff0c;因为我们上架的渠道包基本是定制化混淆出包&#xff0c; 混淆出包有一个关键点就是指定映射文件&#xff0c;映射文件的内容有一部分是使用外部工具在打包前按照一定规律随机生成包名、类名&#xff0c…

flutter使用get库管理路由,并设页面跳转动画和常见动画

get库还是非常强大的一个仓库&#xff0c;里面包含了非常常用的一些方法&#xff0c;比如路由管理&#xff0c;这是最常见和最常用的一个功能了&#xff0c;我们可以先配置一个路由对象&#xff0c;然后在里面配置路由列表&#xff0c;并且设置路由跳转方式。 第一种方式&…

vue3-计算属性

计算属性 模板中的表达式虽然方便&#xff0c;但也只能用来做简单的操作。如果在模板中写太多逻辑&#xff0c;会让模板变得臃肿&#xff0c;难以维护。 根据作者今年是否看过书展示不同信息 <script lang"ts" setup> import { ref, reactive } from "…

java实现局域网内视频投屏播放(五)视频搜索和投屏自动切换下一个

代码链接 这次对ui做了一些调整&#xff0c;整体分成了5个类别分别为 搜索设备播放任务已下载视频列表视频搜索下载任务列表 视频搜索 搜索 点击搜索后&#xff0c;会从执行所有VideoResolver实现类的search方法&#xff0c;将搜索到的结果汇总到一起&#xff0c;根据视频的…

设计模式⑤ :一致性

一、前言 有时候不想动脑子&#xff0c;就懒得看源码又不像浪费时间所以会看看书&#xff0c;但是又记不住&#xff0c;所以决定开始写"抄书"系列。本系列大部分内容都是来源于《 图解设计模式》&#xff08;【日】结城浩 著&#xff09;。该系列文章可随意转载。 …

node-sass@4.7.2 postinstall: `node scripts/build.js`

Can‘t find Python executable “D:\Python36\python.EXE“, you can set the PYTHON env variable.-CSDN博客 gyp ERR! build error gyp ERR! stack Error: C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe failed with exit code: 1 gyp ERR! stack at Chil…

【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化

在FPGA中&#xff0c;大规模数据的存储常常会用到DDR。为了方便用户使用&#xff0c;Xilinx提供了DDR MIG IP核&#xff0c;用户能够通过AXI接口进行DDR的读写访问&#xff0c;然而MIG内部自动实现了许多环节&#xff0c;不利于用户深入理解DDR的底层逻辑。 本文以美光(Micro…

使用emu8086实现——顺序程序设计

一、实验目的 1. 掌握顺序程序设计方法 2. 掌握汇编语言编程设计方法。 二、实验内容 1.用查表的方法将一位十六进制数转换成它相应的ASCII码。 代码及注释&#xff1a; Data segment ;定义数据段Tab db 30h,31h,32h,33h,34h,35,36h,37h,38h,39h ;定义一个Tab的字节型…

云卷云舒:AI for DB、DB for AI

云卷云舒&#xff1a;算力网络云原生&#xff08;下&#xff09;&#xff1a;云数据库发展的新篇章-CSDN博客https://blog.csdn.net/bishenghua/article/details/135050556 随着数据库和AI技术的分支同向演进&#xff0c;AI 和数据库间的关联越发紧密了。 大模型的演进发展&a…

mybatisplus配置

一、新建项目&#xff1a;com.saas.plusdemo 二、配置pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:sch…

借助Gitee将typora图片上传CSDN

概述 前面已经发了一个如何借助Github将typora上的图片上传到csdn上&#xff0c;但这有个缺陷&#xff1a;需要科学上网才能加速查看已经上传到github上的图片&#xff0c;否则就会出现已经上传的图片&#xff0c;无法正常查看的问题 如何解决&#xff1f; 那就可以使用Gite…

WEB 3D技术 three.js 聚光灯

本文 我们来说说 点光源和聚光灯 点光源 就像一个电灯泡一样 想四周发散光 而聚光灯就像手电筒一样 像一个方向射过去 距离越远范围越大 光越弱 我们先来看一个聚光灯的效果 我们可以编写代码如下 import ./style.css import * as THREE from "three"; import { O…