【LLM】從零到一構建一個小型LLM--MiniGPT

從零到一構建一個小型LLM (Small Language Model)暫時起名為MiniGPT。這個模型將專注于因果語言建模 (Causal Language Modeling),這是許多現代LLM(如GPT系列)的核心預訓練任務。


模型設計:

我們設計的模型是一個僅包含解碼器 (Decoder-only) 的Transformer架構,專注于生成式任務。這里將簡化其規模,以使其更易于理解和從頭實現,但保留核心的Transformer組件。

模型架構概覽
  • 輸入層:
    • Token嵌入 (Token Embeddings): 將輸入的離散token轉換為連續向量表示。
    • 位置編碼 (Positional Encoding): 捕獲token在序列中的順序信息。我們將使用絕對位置編碼(例如,正弦位置編碼)。
  • 解碼器塊 (Decoder Block): MiniGPT將由多個相同的解碼器塊堆疊而成。每個解碼器塊包含:
    • 掩碼多頭自注意力層 (Masked Multi-Head Self-Attention Layer): 允許模型關注序列中當前及之前的token,以預測下一個token。這是解碼器獨有的關鍵部分,確保了生成過程的因果性。
    • 層歸一化 (Layer Normalization): 在每個子層操作后應用,有助于訓練穩定。
    • 前饋網絡 (Feed-Forward Network, FFN): 包含兩個線性變換和一個激活函數(例如ReLU或GELU),用于處理注意力層的輸出。
    • 殘差連接 (Residual Connections): 每個子層(注意力層和FFN)的輸出都會與輸入相加,再進行歸一化,有助于解決深度網絡的梯度消失問題。
  • 輸出層:
    • 線性層 (Linear Layer): 將解碼器最終輸出的向量映射回詞匯表大小的維度。
    • Softmax層 (Softmax Layer): 將線性層的輸出轉換為概率分布,表示下一個token是詞匯表中每個詞的概率。
模型參數設定(示例)

為了簡化實現,我們將采用較小的參數:

  • 詞匯表大小 (Vocab Size): 例如,50000(覆蓋常見詞匯)。
  • 嵌入維度 (Embedding Dimension, d_model): 例如,256。
  • 序列最大長度 (Max Sequence Length, max_len): 例如,256。
  • 解碼器塊數量 (Number of Decoder Blocks): 例如,4。
  • 注意力頭數量 (Number of Attention Heads): 例如,4。
  • 前饋網絡維度 (FFN Dimension): 例如,d_model * 4 (1024)。

實現步驟

步驟1:數據預處理與表示
  1. 文本數據準備:
    • 加載小型文本數據集(例如,某個小說或詩歌子集)。
    • 數據清洗與標準化: 轉換為小寫,去除標點符號,處理特殊字符等。
  2. 分詞器實現 (Simple Tokenizer):
    • 實現一個基于字符級 (Character-level)簡單詞級 (Simple Word-level) 的分詞器,以簡化復雜的分詞算法(如BPE)的初期實現。
    • 構建詞匯表 (Vocabulary)token到ID的映射 (Token-to-ID mapping)
    • 實現encodedecode方法。
    • Padding和截斷 (Padding and Truncation): 將所有輸入序列統一到max_len
  3. Token嵌入層:
    • 實現一個PyTorch的nn.Embedding層,將token ID轉換為d_model維的向量。
  4. 位置編碼層:
    • 實現正弦位置編碼 (Sinusoidal Positional Encoding),它可以在不知道序列最大長度的情況下推廣到更長的序列。
**步驟2:注意力機制與Transformer塊 **
  1. 實現Scaled Dot-Product Attention:
    • 定義scaled_dot_product_attention(Q, K, V, mask)函數,包含矩陣乘法、縮放、掩碼應用和softmax。
    • 關鍵是實現mask的應用: 在解碼器中,未來信息是不可見的,所以需要一個下三角矩陣 (Lower Triangular Matrix) 形式的掩碼,將未來token的注意力權重設為負無窮,使其在softmax后變為0。
  2. 實現Multi-Head Attention:
    • 定義MultiHeadAttention模塊,包含多個線性變換(用于Q, K, V的投影),將輸入分為多個頭,并行計算Scaled Dot-Product Attention,然后拼接結果,最后再通過一個線性投影。
  3. 實現Feed-Forward Network (FFN):
    • 定義FeedForward模塊,包含兩個nn.Linear層和一個激活函數。
  4. 實現Decoder Block:
    • 定義DecoderBlock模塊,組合掩碼多頭自注意力層、FFN、層歸一化和殘差連接。
    • 注意殘差連接和層歸一化的正確順序(例如,Post-LN或Pre-LN)。
步驟3:構建MiniGPT模型
  1. 組合Decoder Blocks:
    • MiniGPT主模型類中,實例化Token嵌入層和位置編碼層。
    • 堆疊多個DecoderBlock實例。
  2. 實現輸出層:
    • 一個nn.Linear層將最終解碼器輸出映射到詞匯表維度。
    • 不需要顯式Softmax層,因為CrossEntropyLoss在內部包含了Softmax。
步驟4:訓練與優化
  1. 數據加載器 (DataLoader):
    • 創建數據集類和數據加載器,批量處理輸入序列和對應的目標序列(下一個token)。
  2. 損失函數與優化器:
    • 使用nn.CrossEntropyLoss作為損失函數。
    • 選擇torch.optim.AdamW作為優化器。
  3. 訓練循環 (Training Loop):
    • 實現一個基本的訓練循環,包括前向傳播、損失計算、反向傳播和參數更新。
    • 因果語言建模任務: 輸入序列X,目標是預測X的每個token的下一個token。例如,如果輸入是"hello world",模型會嘗試從"hello"預測"world",并從"hello world"預測下一個token。
  4. 梯度裁剪 (Gradient Clipping):
    • 為防止梯度爆炸,在反向傳播后應用梯度裁剪。
**步驟5:文本生成 (Inference) **
  1. 實現generate方法:
    • 給定一個起始prompt,模型循環預測下一個token。
    • 將預測的token添加到序列中,作為下一個時間步的輸入。
    • 循環直到達到最大生成長度或生成結束符。
    • 采樣策略: 可以實現簡單的貪婪采樣 (Greedy Sampling) 或溫度采樣 (Temperature Sampling)。

核心代碼 (代碼)

import torch
import torch.nn as nn
import torch.nn.functional as F
import math# --- 步驟1: 數據預處理與表示 ---
class SimpleTokenizer:def __init__(self, text):# 簡化版:從文本構建詞匯表self.vocab = sorted(list(set(text)))self.char_to_idx = {ch: i for i, ch in enumerate(self.vocab)}self.idx_to_char = {i: ch for i, ch in enumerate(self.vocab)}self.vocab_size = len(self.vocab)def encode(self, text):return [self.char_to_idx[ch] for ch in text if ch in self.char_to_idx]def decode(self, indices):return "".join([self.idx_to_char[idx] for idx in indices])class PositionalEncoding(nn.Module):def __init__(self, d_model, max_len=5000):super().__init__()pe = torch.zeros(max_len, d_model)position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))pe[:, 0::2] = torch.sin(position * div_term)pe[:, 1::2] = torch.cos(position * div_term)self.register_buffer('pe', pe.unsqueeze(0))def forward(self, x):# x: (batch_size, seq_len, d_model)return x + self.pe[:, :x.size(1)]# --- 步驟2: 注意力機制與Transformer塊 ---
def scaled_dot_product_attention(Q, K, V, mask=None):# Q, K, V: (..., seq_len, d_k)d_k = Q.size(-1)scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k)if mask is not None:scores = scores.masked_fill(mask == 0, float('-inf'))attention_weights = F.softmax(scores, dim=-1)output = torch.matmul(attention_weights, V)return output, attention_weightsclass MultiHeadAttention(nn.Module):def __init__(self, d_model, num_heads):super().__init__()self.d_model = d_modelself.num_heads = num_headsself.d_k = d_model // num_headsself.wq = nn.Linear(d_model, d_model)self.wk = nn.Linear(d_model, d_model)self.wv = nn.Linear(d_model, d_model)self.wo = nn.Linear(d_model, d_model)def forward(self, x, mask=None):batch_size = x.size(0)Q = self.wq(x).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2) # (batch_size, num_heads, seq_len, d_k)K = self.wk(x).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)V = self.wv(x).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)output, attn_weights = scaled_dot_product_attention(Q, K, V, mask)output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model) # Concat headsoutput = self.wo(output)return output, attn_weightsclass FeedForward(nn.Module):def __init__(self, d_model, d_ff):super().__init__()self.linear1 = nn.Linear(d_model, d_ff)self.gelu = nn.GELU() # Or nn.ReLU()self.linear2 = nn.Linear(d_ff, d_model)def forward(self, x):return self.linear2(self.gelu(self.linear1(x)))class DecoderBlock(nn.Module):def __init__(self, d_model, num_heads, d_ff, dropout=0.1):super().__init__()self.self_attn = MultiHeadAttention(d_model, num_heads)self.ffn = FeedForward(d_model, d_ff)self.norm1 = nn.LayerNorm(d_model)self.norm2 = nn.LayerNorm(d_model)self.dropout1 = nn.Dropout(dropout)self.dropout2 = nn.Dropout(dropout)def forward(self, x, tgt_mask):# Masked Multi-Head Self-Attentionattn_output, _ = self.self_attn(x, mask=tgt_mask)x = self.norm1(x + self.dropout1(attn_output)) # Add & Norm# Feed Forwardffn_output = self.ffn(x)x = self.norm2(x + self.dropout2(ffn_output)) # Add & Normreturn x# --- 步驟3: 構建MiniGPT模型 ---
class MiniGPT(nn.Module):def __init__(self, vocab_size, d_model, num_heads, num_layers, d_ff, max_len, dropout=0.1):super().__init__()self.token_embedding = nn.Embedding(vocab_size, d_model)self.positional_encoding = PositionalEncoding(d_model, max_len)self.dropout = nn.Dropout(dropout)self.decoder_layers = nn.ModuleList([DecoderBlock(d_model, num_heads, d_ff, dropout) for _ in range(num_layers)])self.final_norm = nn.LayerNorm(d_model)self.output_linear = nn.Linear(d_model, vocab_size)def generate_square_subsequent_mask(self, sz):mask = torch.triu(torch.ones(sz, sz), diagonal=1).transpose(0, 1)return mask.bool() # Boolean mask for masked_filldef forward(self, src):# src: (batch_size, seq_len)seq_len = src.size(1)tgt_mask = self.generate_square_subsequent_mask(seq_len).to(src.device)x = self.token_embedding(src) # (batch_size, seq_len, d_model)x = self.positional_encoding(x)x = self.dropout(x)for decoder_layer in self.decoder_layers:x = decoder_layer(x, tgt_mask)x = self.final_norm(x)logits = self.output_linear(x) # (batch_size, seq_len, vocab_size)return logitsdef generate(self, tokenizer, prompt, max_new_tokens):self.eval() # Set model to evaluation modeinput_ids = torch.tensor(tokenizer.encode(prompt)).unsqueeze(0) # Add batch dimfor _ in range(max_new_tokens):# If sequence length exceeds max_len, truncate (for simplicity)current_input_ids = input_ids if input_ids.size(1) <= tokenizer.max_len else input_ids[:, -tokenizer.max_len:]with torch.no_grad():logits = self(current_input_ids) # Get logits for the current sequence# Predict the next token based on the last token's logitslast_token_logits = logits[:, -1, :] # (batch_size, vocab_size)# Simple greedy sampling: take the token with the highest probabilitynext_token_id = torch.argmax(last_token_logits, dim=-1).unsqueeze(0) # (1, 1)input_ids = torch.cat((input_ids, next_token_id), dim=1)# Break if generated token is special end token (e.g., <EOS>)# For this simple example, we don't have explicit EOS, just max_new_tokensreturn tokenizer.decode(input_ids[0].tolist())# --- 步驟4: 訓練循環示例 ---
def train_minigpt(model, tokenizer, data, epochs, batch_size, learning_rate, device):optimizer = torch.optim.AdamW(model.parameters(), lr=learning_rate)criterion = nn.CrossEntropyLoss()model.train() # Set model to training mode# Simplified data preparation for training# For a real scenario, you'd have a DataLoader and iterate batches# Here, we'll just process a long string into input/target pairs# Create input-target pairs for causal language modeling# Example: "hello world" -> input: "hello worl", target: "ello world"input_ids_full = torch.tensor(tokenizer.encode(data), dtype=torch.long)for epoch in range(epochs):total_loss = 0num_batches = 0for i in range(0, len(input_ids_full) - model.token_embedding.max_len, batch_size):batch_input = input_ids_full[i : i + model.token_embedding.max_len]batch_target = input_ids_full[i+1 : i + model.token_embedding.max_len + 1] # Shifted targetif len(batch_input) < model.token_embedding.max_len + 1: # Ensure we have input and targetcontinue# For simplicity, if batch_size is 1, and we're processing char by char for a small model# This needs to be adapted for proper batching with padding if sequence lengths vary.# Here, we're assuming fixed max_len for each input chunk.# Reshape for single batchbatch_input = batch_input[:-1].unsqueeze(0).to(device) # Remove last token, add batch dimbatch_target = batch_target.unsqueeze(0).to(device) # Add batch dimoptimizer.zero_grad()logits = model(batch_input) # (batch_size, seq_len, vocab_size)# Reshape logits and targets for CrossEntropyLossloss = criterion(logits.view(-1, logits.size(-1)), batch_target.view(-1))loss.backward()torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) # Gradient clippingoptimizer.step()total_loss += loss.item()num_batches += 1avg_loss = total_loss / num_batchesprint(f"Epoch {epoch+1}/{epochs}, Loss: {avg_loss:.4f}")if __name__ == "__main__":# 示例用法text = "hello world, this is a test string for my minigpt model. " * 100 # Make it longertext += "let's see if it can learn to complete sentences. " * 50tokenizer = SimpleTokenizer(text)# Model parametersvocab_size = tokenizer.vocab_sized_model = 128num_heads = 4num_layers = 2d_ff = d_model * 4max_len = 64 # Max sequence length for our MiniGPT# Adjust tokenizer's max_len based on model's max_lentokenizer.max_len = max_len model = MiniGPT(vocab_size, d_model, num_heads, num_layers, d_ff, max_len)device = torch.device("cuda" if torch.cuda.is_available() else "cpu")model.to(device)print(f"Using device: {device}")print(f"MiniGPT Model created with {sum(p.numel() for p in model.parameters() if p.requires_grad)} trainable parameters.")# Train the model (simplified)# This training setup is very basic for demonstration and would need significant improvements# for actual meaningful learning (e.g., proper dataset iteration, more epochs, larger data)print("\nStarting training...")train_minigpt(model, tokenizer, text, epochs=5, batch_size=16, learning_rate=1e-3, device=device)print("Training complete.")# Generate textprint("\nGenerating text:")prompt = "hello wor"generated_text = model.generate(tokenizer, prompt, max_new_tokens=50)print(generated_text)

模型實現的挑戰與考慮

要想繼續深入,需要解決以下問題,:

  1. 大規模數據處理: 如何高效地讀取、預處理和批量化TB級的數據。
  2. 分布式訓練: 單個GPU無法承載大模型訓練,需要數據并行、模型并行(張量并行、管道并行)等技術。
  3. 內存優化: KV Cache優化、量化、混合精度訓練等。
  4. 模型評估: 除了損失值,還需要針對生成質量、忠實度、一致性等進行定性和定量評估。
  5. 生產部署: 模型推理優化、模型服務框架的選擇和使用。
  6. 超參數調優: 系統化的超參數搜索策略(如網格搜索、隨機搜索、貝葉斯優化)。

通過上述的MiniGPT設計和逐步實現過程,希望讀者將能夠從底層理解LLM的工作原理,為后續深入學習和構建更復雜的大模型打下堅實的基礎。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/89166.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/89166.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/89166.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

網絡安全威脅下的企業困境與破局技術實踐

前言&#xff1a;網絡安全威脅下的企業困境 在數字化轉型的浪潮中&#xff0c;企業對信息技術的依賴程度日益加深&#xff0c;但隨之而來的網絡安全威脅也愈發嚴峻。據統計&#xff0c;全球每年因網絡安全事件造成的經濟損失高達數萬億美元&#xff0c;其中中小企業更是成為了網…

[RAG system] 信息檢索器 | BM25 Vector | Pickle格式 | HybridRetriever重排序

第六章&#xff1a;信息檢索器 在上一章中&#xff0c;我們成功完成了知識庫攝入流程。這是巨大的進步~ 我們精心準備了文檔"塊"&#xff08;類似獨立的索引卡&#xff09;&#xff0c;并將其存儲在兩套智能歸檔系統中&#xff1a;向量數據庫&#xff08;用于基于含…

Android 高通平臺修改音頻參數效果文件-優化音頻效果

Android 高通平臺如何音頻效果 修改音頻參數效果文件-優化音頻效果 按如下方式修改。 開發云 - 一站式云服務平臺 diff --git a/vendor/qcom/proprietary/mm-audio/audcal/family-b/acdbdata//MTP/workspaceFile.qwsp b/vendor/qcom/proprietary/mm-audio/audcal/family-b/acdb…

Install Docker Engine on UbuntuMySQL

Install Docker Engine on Ubuntu&&MySQL安裝docker安裝mysql客戶端連接數據庫我真氣鼠了&#xff0c;今天得到一個血淚的教訓&#xff0c;以后一定看官方文檔&#xff01;&#xff01;&#xff01;學的課用的centos&#xff0c;指令全是yum&#xff0c;我這邊不通用&a…

智能人體感應模塊HC-SR501應用指南---使用esp32

人體熱釋電探頭紅外感應模塊 人體感應開關HC-SR501藍板新款 綠板-淘寶網 HC-SR501 人體紅外感應電子模塊傳感器熱釋電探頭感應開關RD-624-tmall.com天貓 模塊信息 HC-SR501人體感應開關是一種基于紅外線技術的自動控制模塊&#xff0c;廣泛應用于安防、智能家居和自動控制等領…

加速度傳感器方向校準方法

保持平板平放在桌面上&#xff0c;將后置攝像頭保持在平板的左上后方&#xff0c;或者右上后方&#xff0c;此為機器的正方向 1、以一臺重力方向正常的機器做測試&#xff0c;通過DeviceInfoHw這個軟件的加速度測試功能【Accelerometer Test】我們可以知道 X方向數據測試&#…

【OpenHarmonyOS應用開發】

OpenHarmonyOS應用開發1.OpenHarmonyOS應用開發環境安裝2.初始化項目3.連接潤和軟件的開發板套件1.OpenHarmonyOS應用開發環境安裝 進入HarmonyOS下載鴻蒙應用開發工具DevEco Studio 5.0.7.200版本。 雙擊打開下載好的可執行文件&#xff0c;點擊下一步。 如果已經安裝過&am…

50天50個小項目 (Vue3 + Tailwindcss V4) ? | AutoTextEffect(自動打字機)

&#x1f4c5; 我們繼續 50 個小項目挑戰&#xff01;—— AutoTextEffect組件 倉庫地址&#xff1a;https://github.com/SunACong/50-vue-projects 項目預覽地址&#xff1a;https://50-vue-projects.vercel.app/。 利用 Vue 3 的 Composition API 和一些簡單的 CSS 動畫來構…

[RAG] LLM 交互層 | 適配器模式 | 文檔解析器(`docling`庫, CNN, OCR, OpenCV)

第二章&#xff1a;LLM 交互層 在上一章中&#xff0c;我們學習了作為"項目總控"的管道協調器&#xff0c;它負責協調 RAG 系統中各個功能模塊。 其中最重要的協調對象之一&#xff0c;便是負責與大型語言模型&#xff08;LLM&#xff09;進行智能交互的LLM 交互層…

Golang 并發快速上手

文章目錄1. 為什么要用協程&#xff1f;1.1 進程與線程1.2 協程1.3 線程和協程的區別線程協程1.4 Go 協程&#xff08;goroutines&#xff09;和協程&#xff08;coroutines&#xff09;2.Go 協程基本內容2.1 channel2.2 select2.3 future 模式3. 實踐示例3.1 并發處理多個網絡…

ESP32輕松實現UDP無線通信

ESP32支持UDP通信&#xff0c;這是一種輕量級、高效的通信協議&#xff0c;適用于需要快速數據傳輸但對數據可靠性要求不高的場景。以下是關于ESP32如何實現UDP通信的詳細說明&#xff1a; 1. UDP協議簡介及其適用場景 UDP&#xff08;用戶數據報協議&#xff09;是一種無連接的…

Electron實現“僅首次運行時創建SQLite數據庫”

在桌面應用中&#xff0c;SQLite因其輕量、嵌入式特性成為本地存儲的熱門選擇。但若重復初始化數據庫&#xff0c;會導致數據覆蓋或冗余。本文將詳解如何讓Electron應用僅在首次啟動時創建SQLite數據庫&#xff0c;后續啟動直接連接現有庫。一、核心邏輯與實現原理 核心思路&am…

阿里開源AI大模型ThinkSound如何為視頻配上靈魂之聲

目錄 前言 一、當AI解決視頻配音的困境 二、引入“思維鏈”&#xff1a;讓AI像專業音效師一樣思考 三、背后的技術支撐 四、未來ThinkSound會如何改變我們的世界&#xff1f; 總結 &#x1f3ac; 攻城獅7號&#xff1a;個人主頁 &#x1f525; 個人專欄:《AI前沿技術要聞…

圖論(1):多叉樹

多叉樹一、基礎知識1. 圖 & 樹2. 模板2.1 建圖二、簡單循環1. 【模板】樹的路徑求和2. 道路修建&#xff08;改&#xff09;3. 聯合權值4. 毛毛蟲樹三、自頂向下/自底向上1. 醫療中心2. 【模板】樹的直徑3. 【模板】最大子樹和4. 信號放大器一、基礎知識 1. 圖 & 樹 …

樓宇自動化:Modbus 在暖通空調(HVAC)中的節能控制(一)

引言**在當今的建筑領域&#xff0c;樓宇自動化正扮演著愈發關鍵的角色&#xff0c;它致力于提升建筑的舒適度、安全性以及能源效率。而暖通空調&#xff08;HVAC&#xff09;系統作為樓宇自動化中的核心部分&#xff0c;其能耗在整個建筑能耗中占比相當高&#xff0c;據相關數…

【SpringBoot】注冊條件+自動配置原理+自定義starter

注冊條件注入到容器內實體類型對象的屬性都是null&#xff0c;這些對象并沒有什么實際的意義&#xff0c;因為實體類的對象就是來封裝對象的&#xff0c;結果你這些對象中什么都沒有&#xff1b;解決方法是1.給這些屬性賦值然后再注入bean但是這些屬性又是固定的不是很好&#…

Server reports Content-Length Mismatch 的根源與解決方案

“服務器聲明604字節&#xff0c;Yum卻期待28680字節”——當包管理器與倉庫服務器之間的信任崩塌時&#xff0c;會發生什么&#xff1f;問題重現 yum install package_name ... Interrupted by header callback: Server reports Content-Length: 604 but expected size is: 28…

基于 Python/PHP/Node.js 的淘寶 API 商品數據抓取開發教程

在電商數據分析、競品監控等場景中&#xff0c;抓取淘寶商品數據是常見需求。淘寶開放平臺&#xff08;Open Platform&#xff09;提供了標準化的 API 接口&#xff0c;通過合法途徑調用可高效獲取商品信息。本文將分別基于 Python、PHP、Node.js 三種語言&#xff0c;詳解淘寶…

【Tensor的創建】——深度學習.Torch框架

目錄 1 Tensor概述 2 Tensor的創建 2.1 基本的創建方式 2.1.1 torch.tensor 2.1.2 torch.Tensor 2.2 創建線性和隨機張量 2.2.1 創建線性張量 2.2.2 隨機張量 1 Tensor概述 PyTorch會將數據封裝成張量&#xff08;Tensor&#xff09;進行計算&#xff0c;張量就是元素為…

Python腳本批量修復文件時間戳,根據文件名或拍攝日期

實現以下功能 更正文件的 修改時間批量修改指定文件夾中的特定后綴的文件根據文件名中的日期修改&#xff08;優先&#xff09;根據 jpg 文件屬性中的拍攝日期修改根據 mp4 文件屬性中的創建媒體日期修改模擬運行&#xff08;Dry Run&#xff09;模式 依賴 若需要基于jpg文件屬…