主頁 >  其他 > 【動手學深度學習】第十二章筆記:異步計算、資料并行

【動手學深度學習】第十二章筆記:異步計算、資料并行

2023-05-05 09:17:57 其他

為了更好的閱讀體驗,請點擊這里

12.1 編譯器和解釋器

原書主要關注的是命令式編程(imperative programming),Python 是一種解釋性語言,因此沒有編譯器給代碼優化,代碼會跑得很慢,

12.1.1 符號式編程

考慮另一種選擇符號式編程(symbolic programming),即代碼通常只在完全定義了程序之后才執行計算,這個策略被多個深度學習框架使用,包括 Theano 和 TensorFlow(后者已經獲得了命令式編程的擴展),一般包括以下步驟:

  1. 定義計算流程;
  2. 將流程編譯成可執行的程式;
  3. 給定輸入,呼叫編譯好的程式執行,

這將允許進行大量的優化,首先,在大多數情況下,我們可以跳過 Python 解釋器,從而消除因為多個更快的 GPU 與單個 CPU 上的單個 Python 執行緒搭配使用時產生的性能瓶頸,其次,編譯器可以將代碼優化和重寫,因為編譯器在將其轉換為機器指令之前可以看到完整的代碼,所以這種優化是可以實作的,例如,只要某個變數不再需要,編譯器就可以釋放記憶體(或者從不分配記憶體),或者將代碼轉換為一個完全等價的片段,下面,我們將通過模擬命令式編程來進一步了解符號式編程的概念,

def add_():
    return '''
def add(a, b):
    return a + b
'''

def fancy_func_():
    return '''
def fancy_func(a, b, c, d):
    e = add(a, b)
    f = add(c, d)
    g = add(e, f)
    return g
'''

def evoke_():
    return add_() + fancy_func_() + 'print(fancy_func(1, 2, 3, 4))'

prog = evoke_()
print(prog)
y = compile(prog, '', 'exec')
exec(y)
def add(a, b):
    return a + b

def fancy_func(a, b, c, d):
    e = add(a, b)
    f = add(c, d)
    g = add(e, f)
    return g
print(fancy_func(1, 2, 3, 4))
10

里面出現了神奇的兩個函式 compile()exec()

  • compile(source, filename, mode[, flags[, dont_inherit]])
    • source:字串或者 AST(Abstract Syntax Trees)物件
    • filename:代碼檔案名稱,如果不是從檔案讀取代碼則傳遞一些可辨認的值
    • mode:指定編譯代碼的種類,可以指定為 exec, eval, single
    • flags:變數作用域,區域命名空間,如果被提供,可以是任何映射物件
    • flags 和 dont_inherit 是用來控制編譯原始碼時的標志
  • exec(obj)
    • obj:要執行的運算式,

命令式(解釋型)編程和符號式編程的區別如下:

  • 命令式編程更容易使用,在 Python 中,命令式編程的大部分代碼都是簡單易懂的,命令式編程也更容易除錯,這是因為無論是獲取和列印所有的中間變數值,或者使用 Python 的內置除錯工具都更加簡單;
  • 符號式編程運行效率更高,更易于移植,符號式編程更容易在編譯期間優化代碼,同時還能夠將程式移植到與 Python 無關的格式中,從而允許程式在非 Python 環境中運行,避免了任何潛在的與 Python 解釋器相關的性能問題,

12.1.2 混合式編程

PyTorch 是基于命令式編程并且使用動態計算圖,為了能夠利用符號式編程的可移植性和效率,開發人員思考能否將這兩種編程模型的優點結合起來,于是就產生了 TorchScript,TorchScript 允許用戶使用純命令式編程進行開發和除錯,同時能夠將大多數程式轉換為符號式程式,以便在需要產品級計算性能和部署時使用,

接下來假設已經定義好了一個網路比如 net=MLP(),那么可以使用 net = torch.jit.script(net) 代碼使用 TorchScript:

  • torch.jit.script(obj, optimize=None, _frames_up=0, _rcb=None, example_inputs=None)
    • 撰寫一個函式或 nn.Module 腳本將檢查源代碼,使用 TorchScript 編譯器將其編譯為 TorchScript 代碼,并回傳 ScriptModuleScriptFunction, TorchScript 本身是 Python 語言的一個子集,因此并非 Python 中的所有功能都有效,但我們提供了足夠的功能來計算張量并執行依賴于控制的操作,有關完整指南,請參閱 TorchScript 語言參考,
    • 撰寫字典或串列的腳本會將其中的資料復制到 TorchScript 實體中,隨后可以通過參考在 Python 和 TorchScript 之間以零復制開銷傳遞,
    • torch.jit.script() 可以為模塊、函式、字典和串列用作函式,而且還可以被用作裝飾器,
    • 回傳:
      • 如果 objnn.Module,script 會回傳一個 ScriptModule,回傳的 ScriptModule 將與原來的 nn.Module 有相同的子模塊和引數集合,
      • 如果 obj 是獨立的函式,一個 ScriptFunction 將會回傳,
      • 如果 obj 是字典,將會回傳 torch._C.ScriptDict
      • 如果 obj 是串列,將會回傳 torch._C.ScriptList

在使用上面轉化成 TorchScript 的代碼后,一個三層的多層感知機大約增快了 20%,而且,還可以方便地使用 net.save('filepath.pt') 來保存網路結構,眾所周知,普通的 torch.save()/torch.load() 是不能在沒有原本的模塊類定義下讀取模型的,但是在 TorchScript 中,接下來即使我們洗掉了原本的多層感知機的類以及衍生的實體,也可以通過 torch.jit.load('filepath.pt') 重新載入模型,當然也不排除是我沒刪干凈

12.2 異步計算

PyTorch 使用了 Python 自己的調度器來實作不同的性能權衡,對 PyTorch 來說 GPU操 作在默認情況下是異步的,當呼叫一個使用 GPU 的函式時,操作會排隊到特定的設備上,但不一定要等到以后才執行,這允許并行執行更多的計算,包括在 CPU 或其他 GPU 上的操作,

因此,了解異步編程是如何作業的,通過主動地減少計算需求和相互依賴,有助于我們開發更高效的程式,這能夠減少記憶體開銷并提高處理器利用率,下面測驗一下 numpy(CPU) 和 PyTorch(GPU) 的速度,

# GPU計算熱身
device = d2l.try_gpu()
a = torch.randn(size=(1000, 1000), device=device)
b = torch.mm(a, a)

with d2l.Benchmark('numpy'):
    for _ in range(10):
        a = numpy.random.normal(size=(1000, 1000))
        b = numpy.dot(a, a)

with d2l.Benchmark('torch'):
    for _ in range(10):
        a = torch.randn(size=(1000, 1000), device=device)
        b = torch.mm(a, a)
numpy: 1.0981 sec
torch: 0.0011 sec

默認情況下,GPU 操作在 PyTorch 中是異步的,強制 PyTorch 在回傳之前完成所有計算,這種強制說明了之前發生的情況:計算是由后端執行,而前端將控制權回傳給了 Python,

例如下面呼叫 torch.cuda.synchronize(device),這個函式等待在一個 CUDA 設備上所有核的所有流都完成,

with d2l.Benchmark():
    for _ in range(10):
        a = torch.randn(size=(1000, 1000), device=device)
        b = torch.mm(a, a)
    torch.cuda.synchronize(device)
Done: 0.0089 sec

廣義上說,PyTorch 有一個用于與用戶直接互動的前端(例如通過 Python),還有一個由系統用來執行計算的后端,用戶可以用各種前端語言撰寫 PyTorch 程式,如 Python 和 C++,不管使用的前端編程語言是什么,PyTorch 程式的執行主要發生在 C++ 實作的后端,由前端語言發出的操作被傳遞到后端執行,后端管理自己的執行緒,這些執行緒不斷收集和執行排隊的任務,請注意,要使其作業,后端必須能夠跟蹤計算圖中各個步驟之間的依賴關系,因此,不可能并行化相互依賴的操作,

當陳述句的結果需要被列印出來時,Python 前端線程將等待 C++ 后端執行緒完成結果計算,這種設計的一個好處是 Python 前端執行緒不需要執行實際的計算,因此,不管 Python 的性能如何,對程式的整體性能幾乎沒有影響,

練習題

(1)在CPU上,對本節中相同的矩陣乘法操作進行基準測驗,仍然可以通過后端觀察異步嗎?

torch 觀察不到異步現象,反倒是 numpy 可以觀察到異步的現象,雖然 torch.cuda.synchronize(torch.device('cpu')) 會彈出報錯,但是仍然可以使用以下兩個代碼來測驗速度:

with d2l.Benchmark('numpy'):
    for _ in range(10):
        a = numpy.random.normal(size=(1000, 1000))
        b = numpy.dot(a, a)
        
# time.sleep(5)
        
with d2l.Benchmark('torch'):
    for _ in range(10):
        a = torch.randn(size=(1000, 1000), device=device)
        b = torch.mm(a, a)
numpy: 0.9737 sec
torch: 0.2859 sec
with d2l.Benchmark('numpy'):
    for _ in range(10):
        a = numpy.random.normal(size=(1000, 1000))
        b = numpy.dot(a, a)
        
time.sleep(5)
        
with d2l.Benchmark('torch'):
    for _ in range(10):
        a = torch.randn(size=(1000, 1000), device=device)
        b = torch.mm(a, a)
numpy: 0.9414 sec
torch: 0.2103 sec

經過多次嘗試,可以發現 torch 的執行時間有明顯差異,這說明有 numpy 有部分仍然占用設備的時候,已經開始對 torch 的矩陣乘法計時了,

而如果把這兩個矩陣乘法的順序反過來,numpy 的時間變化不大,因此 torch 幾乎沒有異步而 numpy 異步了,

最后,我發現 torch.cuda.synchronize() 直接呼叫不加引數就不會報錯了,如果它的 device 引數為 None,那么它將使用 current_device 函式找出當前設備,

12.3 自動并行

深度學習框架會在后端自動構建計算圖,利用計算圖,系統可以了解所有依賴關系,并且可以選擇性地并行執行多個不相互依賴的任務以提高速度,

通常情況下單個運算子將使用所有CPU或單個GPU上的所有計算資源,并行化對單設備計算機來說并不是很有用,而并行化對于多個設備就很重要了,

請注意,接下來的實驗至少需要兩個GPU來運行,

12.3.1 基于 GPU 的并行計算

測驗一下兩個 GPU 串行各執行 10 次矩陣乘法和并行各執行 10 次矩陣乘法的速度,

devices = d2l.try_all_gpus()
def run(x):
    return [x.mm(x) for _ in range(50)]

x_gpu1 = torch.rand(size=(4000, 4000), device=devices[0])
x_gpu2 = torch.rand(size=(4000, 4000), device=devices[1])
run(x_gpu1)
run(x_gpu2)  # 預熱設備
torch.cuda.synchronize(devices[0])
torch.cuda.synchronize(devices[1])

with d2l.Benchmark('GPU1 time'):
    run(x_gpu1)
    torch.cuda.synchronize(devices[0])

with d2l.Benchmark('GPU2 time'):
    run(x_gpu2)
    torch.cuda.synchronize(devices[1])
GPU1 time: 1.5491 sec
GPU2 time: 1.4804 sec

洗掉兩個任務之間的 torch.cuda.synchronize() 陳述句,系統就可以在兩個設備上自動實作并行計算,

with d2l.Benchmark('GPU1 & GPU2'):
    run(x_gpu1)
    run(x_gpu2)
    torch.cuda.synchronize()
GPU1 & GPU2: 1.5745 sec

12.3.2 并行計算與通信

在許多情況下,我們需要在不同的設備之間移動資料,比如在CPU和GPU之間,或者在不同的GPU之間,

通過在 GPU 上計算,然后將結果復制回 CPU 來模擬這個程序,

def copy_to_cpu(x, non_blocking=False):
    return [y.to('cpu', non_blocking=non_blocking) for y in x]

with d2l.Benchmark('在GPU1上運行'):
    y = run(x_gpu1)
    torch.cuda.synchronize()

with d2l.Benchmark('復制到CPU'):
    y_cpu = copy_to_cpu(y)
    torch.cuda.synchronize()
在GPU1上運行: 1.6285 sec
復制到CPU: 2.5801 sec

在 GPU 仍在運行時就開始使用 PCI-Express 總線帶寬來移動資料是有利的,在 PyTorch 中,to()copy_() 等函式都允許顯式的 non_blocking 引數,這允許在不需要同步時呼叫方可以繞過同步,設定 non_blocking=True 以模擬這個場景,

with d2l.Benchmark('在GPU1上運行并復制到CPU'):
    y = run(x_gpu1)
    y_cpu = copy_to_cpu(y, True)
    torch.cuda.synchronize()
在GPU1上運行并復制到CPU: 1.9456 sec

12.5 多 GPU 訓練

在多個 GPU 上并行總共分為三種:

  1. 網路并行
  2. 按層并行
  3. 資料并行

實際上,資料并行是最常用的方法,原書中也重點討論了資料并行,

12.5.2 資料并行性

假設一臺機器有 \(k\) 個 GPU, 給定需要訓練的模型,雖然每個 GPU 上的引數值都是相同且同步的,但是每個 GPU 都將獨立地維護一組完整的模型引數,

一般來說,\(k\) 個 GPU 并行訓練程序如下:

  • 在任何一次訓練迭代中,給定的隨機的小批量樣本都將被分成 \(k\) 個部分,并均勻地分配到 GPU 上;
  • 每個 GPU 根據分配給它的小批量子集,計算模型引數的損失和梯度;
  • \(k\) 個 GPU 中的區域梯度聚合,以獲得當前小批量的隨機梯度;
  • 聚合梯度被重新分發到每個 GPU 中;
  • 每個 GPU 使用這個小批量隨機梯度,來更新它所維護的完整的模型引數集,

在實踐中請注意,當在 \(k\) 個 GPU 上訓練時,需要擴大小批量的大小為 \(k\) 的倍數,這樣每個 GPU 都有相同的作業量,就像只在單個 GPU 上訓練一樣, 因此,在 16-GPU 服務器上可以顯著地增加小批量資料量的大小,同時可能還需要相應地提高學習率,

12.5.4 資料同步

對于高效的多 GPU 訓練,我們需要兩個基本操作,首先,我們需要向多個設備分發引數并附加梯度(get_params),如果沒有引數,就不可能在 GPU 上評估網路,第二,需要跨多個設備對引數求和,也就是說,需要一個 allreduce 函式,

get_params() 函式定義如下:

def get_params(params, device):
    new_params = [p.to(device) for p in params]
    for p in new_params:
        p.requires_grad_()
    return new_params

假設現在有一個向量分布在多個 GPU 上,下面的 allreduce 函式將所有向量相加,并將結果廣播給所有GPU,請注意,需要將資料復制到累積結果的設備,才能使函式正常作業,

def allreduce(data):
    for i in range(1, len(data)):
        data[0][:] += data[i].to(data[0].device)
    for i in range(1, len(data)):
        data[i][:] = data[0].to(data[i].device)

12.5.5 資料分發

nn.parallel.scatter() 是一個簡單的工具函式,將一個小批量資料均勻地分布在多個 GPU 上,用法如下所示:

data = https://www.cnblogs.com/bringlu/archive/2023/05/04/torch.arange(20).reshape(4, 5)
devices = [torch.device('cuda:0'), torch.device('cuda:1')]
split = nn.parallel.scatter(data, devices)
print('input :', data)
print('load into', devices)
print('output:', split)
input : tensor([[ 0,  1,  2,  3,  4],
        [ 5,  6,  7,  8,  9],
        [10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]])
load into [device(type='cuda', index=0), device(type='cuda', index=1)]
output: (tensor([[0, 1, 2, 3, 4],
        [5, 6, 7, 8, 9]], device='cuda:0'), tensor([[10, 11, 12, 13, 14],
        [15, 16, 17, 18, 19]], device='cuda:1'))

12.5.6 訓練

def train_batch(X, y, device_params, devices, lr):
    X_shards, y_shards = split_batch(X, y, devices)
    # 在每個GPU上分別計算損失
    ls = [loss(lenet(X_shard, device_W), y_shard).sum()
          for X_shard, y_shard, device_W in zip(
              X_shards, y_shards, device_params)]
    for l in ls:  # 反向傳播在每個GPU上分別執行
        l.backward()
    # 將每個GPU的所有梯度相加,并將其廣播到所有GPU
    with torch.no_grad():
        for i in range(len(device_params[0])):
            allreduce(
                [device_params[c][i].grad for c in range(len(devices))])
    # 在每個GPU上分別更新模型引數
    for param in device_params:
        d2l.sgd(param, lr, X.shape[0]) # 在這里,我們使用全尺寸的小批量
     

與前幾章中略有不同:訓練函式需要分配 GPU 并將所有模型引數復制到所有設備,顯然,每個小批量都是使用 train_batch 函式來處理多個 GPU,我們只在一個 GPU 上計算模型的精確度,而讓其他 GPU 保持空閑,盡管這是相對低效的,但是使用方便且代碼簡潔,

def train(num_gpus, batch_size, lr):
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
    devices = [d2l.try_gpu(i) for i in range(num_gpus)]
    # 將模型引數復制到num_gpus個GPU
    device_params = [get_params(params, d) for d in devices]
    num_epochs = 10
    animator = d2l.Animator('epoch', 'test acc', xlim=[1, num_epochs])
    timer = d2l.Timer()
    for epoch in range(num_epochs):
        timer.start()
        for X, y in train_iter:
            # 為單個小批量執行多GPU訓練
            train_batch(X, y, device_params, devices, lr)
            torch.cuda.synchronize()
        timer.stop()
        # 在GPU0上評估模型
        animator.add(epoch + 1, (d2l.evaluate_accuracy_gpu(
            lambda x: lenet(x, device_params[0]), test_iter, devices[0]),))
    print(f'測驗精度:{animator.Y[0][-1]:.2f},{timer.avg():.1f}秒/輪,'
          f'在{str(devices)}')

12.6 多 GPU 的簡潔實作

12.6.1 DataParallel()

原書出現了一個有趣的函式 net = nn.DataParallel(net, device_ids=devices),這個函式可以說是本節的重點,

torch.nn.DataParallel(module, device_ids=None, output_device=None, dim=0) 這個函式:

在模塊的層級上實作了資料并行,

這個容器通過在批次維度中分塊將輸入拆分到指定設備,從而并行化給定模塊的應用程式(其他物件將在每個設備上復制一次),在前向傳遞中,模塊在每個設備上被復制,每個副本處理一部分輸入,在向后傳遞期間,來自每個副本的梯度被匯總到原始模塊中,

批量大小應大于使用的 GPU 數量,

另外,PyTorch 推薦使用 nn.parallel.DistributedDataParallel() 來代替 nn.Parallel(),原因如下:

大多數涉及批量輸入和多個 GPU 的用例應默認使用 DistributedDataParallel 來利用多個 GPU,

使用具有多處理功能的 CUDA 模型有一些重要的注意事項;除非注意準確地滿足資料處理要求,否則您的程式很可能會出現不正確或未定義的行為,

建議使用 DistributedDataParallel,而不是 DataParallel 進行多 GPU 訓練,即使只有一個設備,

DistributedDataParallelDataParallel 之間的區別是:DistributedDataParallel 使用多行程,其中為每個 GPU 創建一個行程,而 DataParallel 使用多執行緒,通過使用 multiprocessing,每個 GPU 都有自己的專用行程,這避免了 Python 解釋器的 GIL 帶來的性能開銷,

如果您使用 DistributedDataParallel,您可以使用 torch.distributed.launch 實用程式來啟動您的程式,請參閱第三方后端,

允許將任意位置和關鍵字輸入傳遞到 DataParallel 中,但某些型別需要特殊處理,張量將依托指定的維度被分開(默認為 0),元組、串列和字典型別將被淺拷貝,其他型別將在不同的執行緒之間共享,如果寫入模型的正向傳播,則可能會被破壞,

在運行此 DataParallel 模塊之前,并行化模塊必須在 device_ids[0] 上具有其引數和緩沖區,原因在于:在每個 forward 中,模塊在每個設備上被復制,因此對 forward 中正在運行的模塊的任何更新都將丟失,例如,如果模塊有一個計數器屬性,在每次轉發時遞增,它將始終保持初始值,因為更新是在轉發后銷毀的副本上完成的,但是,DataParallel 保證 device[0] 上的副本的引數和緩沖區將與基本并行化模塊共享存盤,因此,將記錄對設備 [0] 上的引數或緩沖區的就地更新,例如,BatchNorm2dspectral_norm() 依賴于此行為來更新緩沖區,

當模塊在 forward() 中回傳一個標量時,此 wrapper 將回傳一個長度等于資料并行中使用的設備數量的向量,其中包含每個設備的結果,

引數:

  • module (Module) – 要并行的模塊
  • device_ids (list of python:int or torch.device) – CUDA 設備(默認:全部設備)
  • output_device (int or torch.device) – 輸出的設備位置(默認:device_ids[0])

于是,原書中訓練這段代碼寫成了這樣:

def train(net, num_gpus, batch_size, lr):
    train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size)
    devices = [d2l.try_gpu(i) for i in range(num_gpus)]
    def init_weights(m):
        if type(m) in [nn.Linear, nn.Conv2d]:
            nn.init.normal_(m.weight, std=0.01)
    net.apply(init_weights)
    # 在多個GPU上設定模型
    net = nn.DataParallel(net, device_ids=devices)
    trainer = torch.optim.SGD(net.parameters(), lr)
    loss = nn.CrossEntropyLoss()
    timer, num_epochs = d2l.Timer(), 10
    animator = d2l.Animator('epoch', 'test acc', xlim=[1, num_epochs])
    for epoch in range(num_epochs):
        net.train()
        timer.start()
        for X, y in train_iter:
            trainer.zero_grad()
            X, y = X.to(devices[0]), y.to(devices[0])
            l = loss(net(X), y)
            l.backward()
            trainer.step()
        timer.stop()
        animator.add(epoch + 1, (d2l.evaluate_accuracy_gpu(net, test_iter),))
    print(f'測驗精度:{animator.Y[0][-1]:.2f},{timer.avg():.1f}秒/輪,'
          f'在{str(devices)}')

注意第 \(19\) 行中是把資料傳到了 \(0\) 號 GPU 上,然后它就會自動切成 GPU 個資料塊然后傳過去了,

運行代碼測驗一下!首先是只使用 \(1\) 塊 GPU 的代碼:

train(net, num_gpus=1, batch_size=256, lr=0.1)
測驗精度:0.90,222.1秒/輪,在[device(type='cuda', index=0)]

然后是使用 \(2\) 塊 GPU 的代碼:

train(net, num_gpus=2, batch_size=512, lr=0.2)
測驗精度:0.87,111.8秒/輪,在[device(type='cuda', index=0), device(type='cuda', index=1)]

接近一倍的速度提升,原書中跑一輪居然只需要 \(10\) 秒左右,不禁令人感慨,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/551649.html

標籤:其他

上一篇:FreeSWITCH對接vosk實作實時語音識別

下一篇:返回列表

標籤雲
其他(158442) Python(38117) JavaScript(25399) Java(18012) C(15221) 區塊鏈(8261) C#(7972) AI(7469) 爪哇(7425) MySQL(7157) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5334) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4565) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2432) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1964) Web開發(1951) HtmlCss(1931) python-3.x(1918) 弹簧靴(1913) C++(1912) xml(1889) PostgreSQL(1874) .NETCore(1857) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 【動手學深度學習】第十二章筆記:異步計算、資料并行

    為了更好的閱讀體驗,請點擊這里 12.1 編譯器和解釋器 原書主要關注的是命令式編程(imperative programming)。Python 是一種解釋性語言,因此沒有編譯器給代碼優化,代碼會跑得很慢。 12.1.1 符號式編程 考慮另一種選擇符號式編程(symbolic programmin ......

    uj5u.com 2023-05-05 09:17:57 more
  • FreeSWITCH對接vosk實作實時語音識別

    環境:CentOS 7.6_x64 FreeSWITCH版本 :1.10.9 Python版本:3.9.2 一、背景描述 vosk是一個開源語音識別工具,可識別中文,之前介紹過python使用vosk進行中文語音識別,今天記錄下FreeSWITCH對接vosk實作實時語音識別。 vosk離線語音識別 ......

    uj5u.com 2023-05-05 09:12:31 more
  • 基于MobileNet的人臉表情識別系統(MATLAB GUI版+原理詳解)

    本篇博客介紹了基于MobileNet的人臉表情識別系統,支持圖片識別、視頻識別、攝像頭識別等多種形式,通過GUI界面實作表情識別可視化展示。首先介紹了表情識別任務的背景與意義,總結近年來利用深度學習進行表情識別的相關技術和作業。在資料集選擇上,本文選擇了Fer2013和CK+兩個資料集,并使用MAT... ......

    uj5u.com 2023-05-05 09:06:47 more
  • 從功能測驗轉型測驗開發,薪資漲了20K,1000字講述轉型必經之路...

    身處職場之中,猶如逆水行舟不進則退,想要不被后浪拍死在沙灘上,就要不斷學習新知識,接受新事物。 要得到更好的發展,就要緊跟發展趨勢,不斷轉型才能保持競爭力,在職場中占有一席之地。 轉型不是一件容易的事,涉及到轉型、革新,就要突破現有的框架,必然會經歷陣痛。 我剛作業時就是一名月薪4000軟體測驗工程 ......

    uj5u.com 2023-05-05 09:06:23 more
  • 基于YOLOv5的目標檢測系統詳解(附MATLAB GUI版代碼)

    本文重點介紹了基于YOLOv5目標檢測系統的MATLAB實作,用于智能檢測物體種類并記錄和保存結果,對各種物體檢測結果可視化,提高目標識別的便捷性和準確性。本文詳細闡述了目標檢測系統的原理,并給出MATLAB的實作代碼、預訓練模型,以及GUI界面設計。基于YOLOv5目標檢測演算法,在界面中可以選擇各... ......

    uj5u.com 2023-05-05 09:05:47 more
  • 為什么說測驗崗位是巨坑?10年測驗人告訴你千萬別上當

    每次都有人問我軟體測驗的前景是什么樣的,每年也會有人很多人紛紛涌入測驗的崗位上,希望自己能夠進入阿里、華為等大廠
    但是測驗崗位真的那么吃香嗎?今天我結合從零基礎小白到測驗開發的成長經歷,來說下這個行業的發展前景,以及要入行的同學應該從哪個地方入手學習 ......

    uj5u.com 2023-05-05 09:05:13 more
  • 基于YOLOv4的目標檢測系統(附MATLAB代碼+GUI實作)

    本文介紹了一種MATLAB實作的目標檢測系統代碼,采用 YOLOv4 檢測網路作為核心模型,用于訓練和檢測各種任務下的目標,并在GUI界面中對各種目標檢測結果可視化。文章詳細介紹了YOLOv4的實作程序,包括演算法原理、MATLAB 實作代碼、訓練資料集、訓練程序和圖形用戶界面。在GUI界面中,用戶可... ......

    uj5u.com 2023-05-05 09:04:34 more
  • cPanel XSS漏洞分析研究(CVE-2023-29489)

    cPanel 是一套在網頁寄存業中最享負盛名的商業軟體,是基于于 Linux 和 BSD 系統及以 PHP 開發且性質為閉源軟體;提供了足夠強大和相當完整的主機管理功能,諸如:Webmail 及多種電郵協議、網頁化 FTP 管理、SSH 連線、資料庫管理系統、DNS 管理等遠端網頁式主機管理軟體功能... ......

    uj5u.com 2023-05-05 09:04:11 more
  • 博客開通

    之前因為查資料注冊的博客園,今天第一次開通屬于自己的博客,小小的記錄一下未來。 #include<iostream> using namespace std; int main(){ print("Hello world!"); return 0; } 我現在大四馬上畢業,考研失敗,對春招的認識不夠 ......

    uj5u.com 2023-05-05 09:03:59 more
  • 京東物流常態化壓測實踐

    大促備戰壓測備戰時間緊、任務多,壓測備戰壓力較大,在大促備戰多專項并行資源緊張情況下,頻繁的系統調優給整個大促帶來不可控的風險因素。引入常態化壓測的手段,通過每周或每月的定期壓測行為,持續把控系統性能表現,保證服務穩定性;同時將需求上線引起的性能問題前置暴露,及時定位優化問題;減輕備戰壓力,提升壓測... ......

    uj5u.com 2023-05-05 09:03:54 more