paint-brush
Жылжымалы нүктелік математика бойынша терең оқыту. Бұл қате болса ше?бойынша@abhiyanampally_kob9nse8
549 оқулар
549 оқулар

Жылжымалы нүктелік математика бойынша терең оқыту. Бұл қате болса ше?

бойынша 40m2025/02/11
Read on Terminal Reader

Тым ұзақ; Оқу

Логарифмдік санау жүйесі (LNS) өзгермелі нүкте (FP) арифметикасына балама сандық ұсыну болып табылады. LNS логарифмдік шкаладағы сандарды көрсетеді, көбейтулерді қосымшаларға түрлендіреді, бұл белгілі бір аппараттық архитектураларда есептеу жағынан арзанырақ болуы мүмкін. Дегенмен, LNS жүйесінде қосу және азайту дәлдіктің төмендеуіне әкелетін жуықтауларды қажет етеді. Біз MNIST жүйесінде қарапайым толық қосылған көп қабатты перцептронды үйрету үшін LNS пайдаланамыз.
featured image - Жылжымалы нүктелік математика бойынша терең оқыту. Бұл қате болса ше?
undefined HackerNoon profile picture
0-item
1-item

Мен логарифмдік санау жүйесін (LNS) терең оқытуда пайдалану идеясын алғаш рет кездестіргенде, мені қызықтырды, бірақ сонымен бірге күмәндандым. Көпшілігіміз сияқты мен әрқашан терең оқытудағы сандық есептеу стандарты болып табылатын Floating-Point (FP) арифметикасымен жұмыс істедім. FP дәлдік пен диапазон арасындағы жақсы тепе-теңдікті қамтамасыз етеді, бірақ ол айырбастаулармен бірге келеді: жадты жоғары пайдалану, есептеу күрделілігінің жоғарылауы және қуатты тұтыну. Сонымен, мен тәжірибе жасап, өз көзіммен көруді шештім — MNIST жүйесінде қарапайым толық қосылған көп қабатты перцептронды (MLP) жаттықтыру кезінде LNS FP-мен қалай салыстырылады?

Неліктен LNS туралы ойлану керек?

LNS логарифмдік шкаладағы сандарды көрсетеді, көбейтуді қосуға түрлендіреді, бұл белгілі бір аппараттық архитектураларда есептеу жағынан арзанырақ болуы мүмкін. Бұл тиімділік дәлдік құнына, әсіресе LNS жүйесінде күрделірек болатын қосу және алу операцияларына байланысты. Дегенмен, әлеуетті артықшылықтар — жад ізін азайту, жылдам есептеулер және аз қуат тұтыну — мені оны сынап көру үшін қызықтырды.

Фон: Қалқымалы нүкте және логарифмдік санау жүйесі

Floating Point (FP) ұсыну

Қалқымалы нүкте арифметикасы PyTorch және TensorFlow сияқты терең оқыту жүйелерінің көпшілігінде стандартты сандық көрініс болып табылады. FP нөмірлері бар:


  • Белгі биті (оң немесе теріс мәнді анықтау)
  • Көрсеткіш (масштабтау коэффициенті)
  • Мантисса (мәні) (санның дәлдігі)


FP32 (бір дәлдік) сандық дәлдік пен есептеу тиімділігі арасындағы тепе-теңдікті қамтамасыз ететін терең оқытуда жиі қолданылады. FP16 және BF16 сияқты тиімдірек пішімдері жаттығуды жеделдету үшін танымал болуда.

Логарифмдік санау жүйесі (LNS)

LNS — сандар логарифмдер ретінде сақталатын балама сандық көрініс: [ x = \log_b (y) ] мұндағы ( b ) логарифм негізі. LNS бірнеше артықшылықтары бар:


  • Көбейту қосуға оңайлатылған : ( x_1 * x_2 = b^{(\log_b x_1 + \log_b x_2)} )
  • Бөлу азайтуға оңайлатылған : ( x_1 / x_2 = b^{(\log_b x_1 - \log_b x_2)} )
  • Экспоненциалды өсу функциялары сызықты болады


Дегенмен, LNS жүйесінде қосу және азайту дәлдіктің төмендеуіне әкелетін жуықтауларды қажет етеді.

LNS арифметикалық амалдары

LNS-ті әрі қарай зерттеу үшін мен LNS ішкі көріністерін пайдаланып қосу, алу, көбейту және бөлу сияқты негізгі арифметикалық амалдарды орындадым.


 import torch import numpy as np import xlns as xl # Assuming xlns module is installed and provides xlnsnp # Function to convert floating-point numbers to xlns internal representation def float_to_internal(arr): xlns_data = xl.xlnsnp(arr) return xlns_data.nd # Function to convert xlns internal representation back to floating-point numbers def internal_to_float(internal_data): original_numbers = [] for value in internal_data: x = value // 2 s = value % 2 # Use x and s to create xlns object xlns_value = xl.xlns(0) xlns_value.x = x xlns_value.s = s original_numbers.append(float(xlns_value)) return original_numbers # Function to perform LNS addition using internal representation def lns_add_internal(x, y): max_part = torch.maximum(x, y) diff = torch.abs(x - y) adjust_term = torch.log1p(torch.exp(-diff)) return max_part + adjust_term # Function to perform LNS subtraction using internal representation def lns_sub_internal(x, y): return lns_add_internal(x, -y) # Function to perform LNS multiplication using internal representation def lns_mul_internal(x, y): return x + y # Function to perform LNS division using internal representation def lns_div_internal(x, y): return x - y # Input floating-point arrays x_float = [2.0, 3.0] y_float = [-1.0, 0.0] # Convert floating-point arrays to xlns internal representation x_internal = float_to_internal(x_float) y_internal = float_to_internal(y_float) # Create tensors from the internal representation tensor_x_nd = torch.tensor(x_internal, dtype=torch.int64) tensor_y_nd = torch.tensor(y_internal, dtype=torch.int64) # Perform the toy LNS addition on the internal representation result_add_internal = lns_add_internal(tensor_x_nd, tensor_y_nd) # Perform the toy LNS subtraction on the internal representation result_sub_internal = lns_sub_internal(tensor_x_nd, tensor_y_nd) # Perform the toy LNS multiplication on the internal representation result_mul_internal = lns_mul_internal(tensor_x_nd, tensor_y_nd) # Perform the toy LNS division on the internal representation result_div_internal = lns_div_internal(tensor_x_nd, tensor_y_nd) # Convert the internal results back to original floating-point values result_add_float = internal_to_float(result_add_internal.numpy()) result_sub_float = internal_to_float(result_sub_internal.numpy()) result_mul_float = internal_to_float(result_mul_internal.numpy()) result_div_float = internal_to_float(result_div_internal.numpy()) # Convert the results back to PyTorch tensors result_add_tensor = torch.tensor(result_add_float, dtype=torch.float32) result_sub_tensor = torch.tensor(result_sub_float, dtype=torch.float32) result_mul_tensor = torch.tensor(result_mul_float, dtype=torch.float32) result_div_tensor = torch.tensor(result_div_float, dtype=torch.float32) # Print results print("Input x:", x_float) print("Input y:", y_float) print("Addition Result:", result_add_float) print("Addition Result Tensor:", result_add_tensor) print("Subtraction Result:", result_sub_float) print("Subtraction Result Tensor:", result_sub_tensor) print("Multiplication Result:", result_mul_float) print("Multiplication Result Tensor:", result_mul_tensor) print("Division Result:", result_div_float) print("Division Result Tensor:", result_div_tensor)


Міне, менің логарифмдік санау жүйесін (LNS) тәжірибелік енгізуімнің қысқаша мазмұны.

1. PyTorch жүйесіндегі негізгі LNS тұжырымдамасы және қиындықтары

LNS жүйесінде сандар көбейту мен бөлуді қосу мен азайтуға түрлендіретін логарифмдер түрінде берілген. Дегенмен, мұны PyTorch көмегімен жүзеге асыру нақты қиындықтарды тудырады, өйткені PyTorch тензорлары өзгермелі нүкте көріністерін іштей пайдаланады. Бұл бірнеше талаптарды тудырады:


  • Есептеу кезінде логарифмдік көріністі сақтаңыз.
  • Сандық тұрақтылықты қамтамасыз ету.
  • Түрлендірулерді мұқият өңдеңіз.
  • Екі құрамдас арқылы ішкі көріністі басқарыңыз:
    • x : логарифмдік мән.
    • s : белгі биті (0 немесе 1).

2. Ішкі өкілдік және конверсия

Бірінші қадам өзгермелі нүкте сандарын олардың LNS ішкі көрінісіне түрлендіру болып табылады.

 import torch import numpy as np import xl # Hypothetical external LNS library def float_to_internal(arr): xlns_data = xl.xlnsnp(arr) return xlns_data.nd # Convert floating-point arrays to xlns internal representation x_float = np.array([2.0, 3.0]) y_float = np.array([-1.0, 0.0]) x_internal = float_to_internal(x_float) y_internal = float_to_internal(y_float) # Create tensors from the internal representation tensor_x_nd = torch.tensor(x_internal, dtype=torch.int64) tensor_y_nd = torch.tensor(y_internal, dtype=torch.int64)


dtype=torch.int64 пайдалану өте маңызды, себебі:

  • Ол өзгермелі нүктелі дөңгелектеу қателерінсіз нақты LNS ішкі көрінісін сақтайды.
  • Логарифмдік мәнді де, таңба битін де бір бүтін санға қосады.
  • Қажетсіз өзгермелі нүкте әрекеттерінің LNS көрінісін бұзуына жол бермейді.

3. Негізгі арифметикалық амалдар

а) Көбейту

 def lns_mul_internal(x, y): return x + y

LNS ішіндегі көбейту қосуға айналады:

  • Егер a = log(x) және b = log(y) болса, онда log(x×y) = log(x) + log(y) .

б) Бөлу

 def lns_div_internal(x, y): return x - y

Бөлу азайтуға айналады:

  • log(x/y) = log(x) - log(y) .

в) Қосу

 def lns_add_internal(x, y): max_part = torch.maximum(x, y) diff = torch.abs(x - y) adjust_term = torch.log1p(torch.exp(-diff)) return max_part + adjust_term


Қосу күрделірек және сандық жағынан сезімтал, себебі:

  • Ол көрсеткіштік және логарифмдік амалдарды қамтиды.
  • Тікелей өзгермелі нүктені енгізу толып кетуге/толып кетуге әкелуі мүмкін.
  • Теңдеуді пайдаланады: log(x + y) = log(max(x,y)) + log(1 + exp(log(min(x,y)) - log(max(x,y)))) .
  • Жақсырақ сандық тұрақтылық үшін тікелей log(1 + x) орнына log1p пайдаланады.

4. Қауіпсіздік және түрлендіруді басқару түрі

 def internal_to_float(internal_data): for value in internal_data: x = value // 2 # Integer division s = value % 2 # Integer modulo


Түрлендіру құбыры нақты бөлуді сақтайды:

  1. Float → LNS ішкі көрінісінен түрлендіру (бүтін сандар).
  2. Бүтін арифметика арқылы LNS операцияларын орындаңыз.
  3. Қажет болғанда ғана қалқымалы күйге қайта түрлендіру.
 # Convert results back to float and tensor result_add_float = internal_to_float(result_add_internal.numpy()) result_add_tensor = torch.tensor(result_add_float, dtype=torch.float32)

5. Негізгі артықшылықтар мен шектеулер

Артықшылықтары

  • Көбейту және бөлу қосу және азайтуға оңайлатылған .
  • Бекітілген нүктелік арифметикасы бар кең динамикалық диапазон .
  • Белгілі бір қолданбалар үшін тиімдірек .

Шектеулер

  • Қосу және алу күрделірек амалдар.
  • Жылжымалы нүкте мен LNS арасындағы конверсиялық үстеме шығындар .
  • Нөлдік және теріс сандар үшін арнайы өңдеуді қажет етеді .
  • PyTorch тензорының үйлесімділігі түрді мұқият басқаруды қажет етеді.

6. Оңтайландыру мүмкіндіктері

Өнімділікті жақсарту үшін келесі әрекеттерді орындауға болады:

  1. LNS операциялары үшін теңшелетін PyTorch autograd функциясын іске қосыңыз.
  2. LNS қолдайтын теңшелетін тензор түрін жасаңыз.
  3. GPU жүйесінде тиімді LNS операциялары үшін CUDA ядроларын пайдаланыңыз.


Ағымдағы енгізу практикалық айырбастарды жасайды:

  • Максималды өнімділікке қарағанда айқындылық пен тұрақтылыққа басымдық береді.
  • LNS дәлдігін сақтай отырып, PyTorch бар тензорлық инфрақұрылымын пайдаланады.
  • Түрді мұқият басқару арқылы сандық тұрақтылықты сақтайды.
  • Көріністер арасындағы түрлендірулерді азайтады.

7. Деректер ағынының мысалы

Келесі қадамдар [2.0, 3.0] және [-1.0, 0.0] мысал мәндерін қолданып толық құбырды көрсетеді:

  1. Кіріс қалқымалы мәндерін LNS ішкі көрінісіне түрлендіру.
  2. LNS мәндерін сақтау үшін бүтін тензорларды жасаңыз.
  3. LNS доменінде арифметикалық амалдарды орындаңыз.
  4. Нәтижелерді өзгермелі нүктеге қайта түрлендіру.
  5. Әрі қарай өңдеу үшін соңғы PyTorch тензорларын жасаңыз.


Бұл іске асыру сандық тұрақтылық пен дәлдікті сақтай отырып, PyTorch қалқымалы нүктелі тензор жүйесі мен LNS арифметикасының арасындағы алшақтықты сәтті өтейді.


FP және LNS көмегімен MNIST Digit деректер жинағында толық қосылған MLP-ді үйрету

Экспериментті орнату

Мен MNIST деректер жинағында FP және LNS өкілдіктерін пайдалана отырып, толық қосылған MLP оқыттым. Модельдің архитектурасы қарапайым болды:

  • Кіріс қабаты: 784 нейрон (28x28 тегістелген кескіндер)
  • Жасырын қабаттар: 256 және 128 нейрондары бар екі қабат, ReLU активациялары
  • Шығару деңгейі: 10 нейрон (әр сан үшін бір, softmax көмегімен)
  • Жоғалту функциясы: кросс-энтропия
  • Оңтайландырушы: Адам


LNS енгізу үшін маған әдеттегі PyTorch жұмыс үрдісінен шығуға тура келді. PyTorch қолдайтын FP-ден айырмашылығы, PyTorch кірістірілген LNS операцияларын қамтамасыз етпейді. Мен логарифмдік сандарды ұсыну мен арифметиканы жүзеге асыратын, нейрондық желілерде LNS пайдалануға мүмкіндік беретін xlns деп аталатын GitHub жобасын таптым.

PyTorch ішіндегі Floating-Point MLP

Біз PyTorch көмегімен стандартты FP негізінде толық қосылған MLP енгізуден бастаймыз:

 import torch import torch.nn as nn import torch.optim as optim import torchvision import torchvision.transforms as transforms import matplotlib.pyplot as plt import numpy as np import time # For calculating elapsed time # Define the multi-layer perceptron (MLP) model with one hidden layer class MLP(nn.Module): def __init__(self): super(MLP, self).__init__() # Input: 28*28 features; Hidden layer: 100 neurons; Output layer: 10 neurons self.fc1 = nn.Linear(28 * 28, 100) self.relu = nn.ReLU() self.fc2 = nn.Linear(100, 10) self.logsoftmax = nn.LogSoftmax(dim=1) # For stable outputs with NLLLoss def forward(self, x): # Flatten image: (batch_size, 1, 28, 28) -> (batch_size, 784) x = x.view(x.size(0), -1) x = self.fc1(x) x = self.relu(x) x = self.fc2(x) return self.logsoftmax(x) def train_and_validate(num_epochs=5, batch_size=64, learning_rate=0.01, split_ratio=0.8): # Set the device to GPU if available device = torch.device("cuda" if torch.cuda.is_available() else "cpu") print(f"Training on device: {device}") # Transformation for MNIST: convert to tensor and normalize transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) # Load the MNIST training dataset train_dataset_full = torchvision.datasets.MNIST( root='./data', train=True, transform=transform, download=True ) # Split the dataset into training and validation sets n_total = len(train_dataset_full) n_train = int(split_ratio * n_total) n_val = n_total - n_train train_dataset, val_dataset = torch.utils.data.random_split(train_dataset_full, [n_train, n_val]) # Create DataLoaders for training and validation datasets train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True) val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=batch_size, shuffle=False) # Initialize the model, loss function, and optimizer; move model to device model = MLP().to(device) criterion = nn.NLLLoss() optimizer = optim.SGD(model.parameters(), lr=learning_rate) # Lists to store training and validation accuracies for each epoch train_accuracies = [] val_accuracies = [] # Record the start time for measuring elapsed time start_time = time.time() # Training loop for epoch in range(num_epochs): model.train() running_loss = 0.0 correct_train = 0 total_train = 0 for inputs, labels in train_loader: # Move inputs and labels to device inputs, labels = inputs.to(device), labels.to(device) optimizer.zero_grad() outputs = model(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() # Compute running loss and training accuracy running_loss += loss.item() * inputs.size(0) _, predicted = torch.max(outputs.data, 1) total_train += labels.size(0) correct_train += (predicted == labels).sum().item() train_accuracy = 100.0 * correct_train / total_train train_accuracies.append(train_accuracy) # Evaluate on validation set model.eval() correct_val = 0 total_val = 0 with torch.no_grad(): for inputs, labels in val_loader: inputs, labels = inputs.to(device), labels.to(device) outputs = model(inputs) _, predicted = torch.max(outputs.data, 1) total_val += labels.size(0) correct_val += (predicted == labels).sum().item() val_accuracy = 100.0 * correct_val / total_val val_accuracies.append(val_accuracy) print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss/total_train:.4f}, " f"Train Acc: {train_accuracy:.2f}%, Val Acc: {val_accuracy:.2f}%") # Calculate elapsed time elapsed_time = time.time() - start_time print(f"Training completed in {elapsed_time:.2f} seconds.") # Show sample predictions from the validation set show_predictions(model, val_loader, device) # Optional: plot training and validation accuracies epochs_arr = np.arange(1, num_epochs + 1) plt.figure(figsize=(10, 6)) plt.plot(epochs_arr, train_accuracies, label='Training Accuracy', marker='o') plt.plot(epochs_arr, val_accuracies, label='Validation Accuracy', marker='x') plt.xlabel('Epoch') plt.ylabel('Accuracy (%)') plt.title('Training and Validation Accuracies') plt.legend() plt.grid(True) plt.savefig('pytorch_accuracy.png') plt.show() def show_predictions(model, data_loader, device, num_images=6): """ Displays a few sample images from the data_loader along with the model's predictions. """ model.eval() images_shown = 0 plt.figure(figsize=(12, 8)) # Get one batch of images from the validation dataset for inputs, labels in data_loader: inputs, labels = inputs.to(device), labels.to(device) with torch.no_grad(): outputs = model(inputs) _, predicted = torch.max(outputs, 1) # Loop through the batch and plot images for i in range(inputs.size(0)): if images_shown >= num_images: break # Move the image to cpu and convert to numpy for plotting img = inputs[i].cpu().squeeze() plt.subplot(2, num_images // 2, images_shown + 1) plt.imshow(img, cmap='gray') plt.title(f"Pred: {predicted[i].item()}") plt.axis('off') images_shown += 1 if images_shown >= num_images: break plt.suptitle("Sample Predictions from the Validation Set") plt.tight_layout() plt.show() if __name__ == '__main__': train_and_validate(num_epochs=5, batch_size=64, learning_rate=0.01, split_ratio=0.8)


Бұл енгізу көбейту мен қосулар FP арифметикасымен өңделетін кәдімгі терең оқыту құбырынан кейін жүреді.


Мұнда MNIST деректер жинағы үшін көп деңгейлі перцептронды (MLP) осы PyTorch іске асырудың егжей-тегжейлі шолуы берілген.

  1. Модельдік архитектура (MLP сыныбы):
 class MLP(nn.Module): def __init__(self): super(MLP, self).__init__() self.fc1 = nn.Linear(28 * 28, 100) # First fully connected layer self.relu = nn.ReLU() # Activation function self.fc2 = nn.Linear(100, 10) # Output layer self.logsoftmax = nn.LogSoftmax(dim=1)
  1. Алға өту:
 def forward(self, x): x = x.view(x.size(0), -1) # Flatten: (batch_size, 1, 28, 28) -> (batch_size, 784) x = self.fc1(x) # First layer x = self.relu(x) # Activation x = self.fc2(x) # Output layer return self.logsoftmax(x) # Final activation
  1. Жаттығуды орнату:
 def train_and_validate(num_epochs=5, batch_size=64, learning_rate=0.01, split_ratio=0.8): device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # Data preprocessing transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) # Normalize to [-1, 1] ])

Негізгі компоненттер:

  • Құрылғыны таңдау арқылы GPU қолдауы

  • Жаттығуды жақсарту үшін деректерді қалыпқа келтіру

  • Конфигурацияланатын гиперпараметрлер


  1. Деректер жиынын басқару:
 train_dataset_full = torchvision.datasets.MNIST( root='./data', train=True, transform=transform, download=True ) # Split into train/validation n_train = int(split_ratio * n_total) train_dataset, val_dataset = torch.utils.data.random_split(train_dataset_full, [n_train, n_val])
  • Егер жоқ болса, MNIST деректер жинағын жүктеп алады

  • Деректерді оқыту (80%) және тексеру (20%) жиындарына бөледі


  1. Жаттығу циклі:
 for epoch in range(num_epochs): model.train() for inputs, labels in train_loader: inputs, labels = inputs.to(device), labels.to(device) optimizer.zero_grad() # Clear gradients outputs = model(inputs) # Forward pass loss = criterion(outputs, labels)# Calculate loss loss.backward() # Backward pass optimizer.step() # Update weights

Классикалық жаттығу процедурасы:

  • Нөлдік градиенттер

  • Алға өту

  • Шығындарды есептеу

  • Артқа өту

  • Салмақ жаңартулары


  1. Тексеру:
 model.eval() with torch.no_grad(): for inputs, labels in val_loader: outputs = model(inputs) _, predicted = torch.max(outputs.data, 1) total_val += labels.size(0) correct_val += (predicted == labels).sum().item()

Негізгі мүмкіндіктер:

  • Модель бағалау режиміне орнатылды

  • Градиентті есептеу қажет емес

  • Дәлдік есептеу


  1. Көрнекілігі:
 def show_predictions(model, data_loader, device, num_images=6): model.eval() plt.figure(figsize=(12, 8)) # Display predictions vs actual labels
  • Тексеру жиынынан үлгі болжамдарын көрсетеді

  • Сапалық бағалау үшін пайдалы


  1. Өнімділікті қадағалау:
 # Training metrics train_accuracies.append(train_accuracy) val_accuracies.append(val_accuracy) # Plot learning curves plt.plot(epochs_arr, train_accuracies, label='Training Accuracy') plt.plot(epochs_arr, val_accuracies, label='Validation Accuracy')
  • Жаттығу және тексеру дәлдігін қадағалайды

  • Оқу қисықтарының сызбасын салады

  • Жаттығу уақытын өлшейді


Бұл LNS негізіндегі енгізулермен салыстыру үшін берік негіз береді, өйткені ол дәстүрлі өзгермелі нүкте арифметикасы арқылы терең оқыту құбырының барлық стандартты құрамдастарын жүзеге асырады.

Логарифмдік санау жүйесі (LNS) MLP

LNS үшін біз xlns кітапханасын пайдалануымыз керек. FP-ден айырмашылығы, LNS көбейтуді қажет ететін операцияларды логарифмдік домендегі қосумен ауыстырады. Дегенмен, PyTorch мұны жергілікті түрде қолдамайды, сондықтан қажет болған жағдайда LNS операцияларын қолмен қолдануымыз керек.

 import numpy as np import matplotlib.pyplot as plt import os import time import argparse import xlns as xl from tensorflow.keras.datasets import mnist # Use Keras's MNIST loader # If you are using fractional normalized LNS, make sure the following are uncommented import xlnsconf.xlnsudFracnorm xlnsconf.xlnsudFracnorm.ilog2 = xlnsconf.xlnsudFracnorm.ipallog2 xlnsconf.xlnsudFracnorm.ipow2 = xlnsconf.xlnsudFracnorm.ipalpow2 # Set global parameter in xlns xl.xlnssetF(10) def softmax(inp): max_vals = inp.max(axis=1) max_vals = xl.reshape(max_vals, (xl.size(max_vals), 1)) u = xl.exp(inp - max_vals) v = u.sum(axis=1) v = v.reshape((xl.size(v), 1)) u = u / v return u def main(main_params): print("arbitrary base np LNS. Also xl.hstack, xl routines in softmax") print("testing new softmax and * instead of @ for delta") print("works with type " + main_params['type']) is_training = bool(main_params['is_training']) leaking_coeff = float(main_params['leaking_coeff']) batchsize = int(main_params['minibatch_size']) lr = float(main_params['learning_rate']) num_epoch = int(main_params['num_epoch']) _lambda = float(main_params['lambda']) ones = np.array(list(np.ones((batchsize, 1)))) if is_training: # Load the MNIST dataset from Keras (x_train, y_train), (x_test, y_test) = mnist.load_data() # Normalize images to [0, 1] x_train = x_train.astype(np.float64) / 255.0 x_test = x_test.astype(np.float64) / 255.0 # One-hot encode the labels (assume 10 classes for MNIST digits 0-9) num_classes = 10 y_train = np.eye(num_classes)[y_train] y_test = np.eye(num_classes)[y_test] # Flatten the images from (28, 28) to (784,) x_train = x_train.reshape(x_train.shape[0], -1) x_test = x_test.reshape(x_test.shape[0], -1) # Use a portion of the training data for validation (the 'split' index) split = int(main_params['split']) x_val = x_train[split:] y_val = y_train[split:] x_train = x_train[:split] y_train = y_train[:split] # If available, load pretrained weights; otherwise, initialize new random weights. if os.path.isfile("./weightin.npz"): print("using ./weightin.npz") randfile = np.load("./weightin.npz", "r") W1 = randfile["W1"] W2 = randfile["W2"] randfile.close() else: print("using new random weights") # Note: The input layer now has 785 neurons (784 features + 1 bias). W1 = np.array(list(np.random.normal(0, 0.1, (785, 100)))) # The first hidden layer has 100 neurons; add bias so 101 W2 = np.array(list(np.random.normal(0, 0.1, (101, 10)))) np.savez_compressed("./weightout.npz", W1=W1, W2=W2) delta_W1 = np.array(list(np.zeros(W1.shape))) delta_W2 = np.array(list(np.zeros(W2.shape))) # Convert weights to desired type (xlns variants or float) if main_params['type'] == 'xlnsnp': lnsW1 = xl.xlnsnp(np.array(xl.xlnscopy(list(W1)))) lnsW2 = xl.xlnsnp(np.array(xl.xlnscopy(list(W2)))) lnsones = xl.xlnsnp(np.array(xl.xlnscopy(list(np.ones((batchsize, 1)))))) lnsdelta_W1 = xl.xlnsnp(np.array(xl.xlnscopy(list(np.zeros(W1.shape))))) lnsdelta_W2 = xl.xlnsnp(np.array(xl.xlnscopy(list(np.zeros(W2.shape))))) elif main_params['type'] == 'xlnsnpv': lnsW1 = xl.xlnsnpv(np.array(xl.xlnscopy(list(W1))), 6) lnsW2 = xl.xlnsnpv(np.array(xl.xlnscopy(list(W2))), 6) lnsones = xl.xlnsnpv(np.array(xl.xlnscopy(list(np.ones((batchsize, 1)))))) lnsdelta_W1 = xl.xlnsnpv(np.array(xl.xlnscopy(list(np.zeros(W1.shape))))) lnsdelta_W2 = xl.xlnsnpv(np.array(xl.xlnscopy(list(np.zeros(W2.shape))))) elif main_params['type'] == 'xlnsnpb': lnsW1 = xl.xlnsnpb(np.array(xl.xlnscopy(list(W1))), 2**2**-6) lnsW2 = xl.xlnsnpb(np.array(xl.xlnscopy(list(W2))), 2**2**-6) lnsones = xl.xlnsnpb(np.array(xl.xlnscopy(list(np.ones((batchsize, 1))))), 2**2**-xl.xlnsF) lnsdelta_W1 = xl.xlnsnpb(np.array(xl.xlnscopy(list(np.zeros(W1.shape)))), 2**2**-xl.xlnsF) lnsdelta_W2 = xl.xlnsnpb(np.array(xl.xlnscopy(list(np.zeros(W2.shape)))), 2**2**-xl.xlnsF) elif main_params['type'] == 'xlns': lnsW1 = np.array(xl.xlnscopy(list(W1))) lnsW2 = np.array(xl.xlnscopy(list(W2))) lnsones = np.array(xl.xlnscopy(list(np.ones((batchsize, 1))))) lnsdelta_W1 = np.array(xl.xlnscopy(list(np.zeros(W1.shape)))) lnsdelta_W2 = np.array(xl.xlnscopy(list(np.zeros(W2.shape)))) elif main_params['type'] == 'xlnsud': lnsW1 = np.array(xl.xlnscopy(list(W1), xl.xlnsud)) lnsW2 = np.array(xl.xlnscopy(list(W2), xl.xlnsud)) lnsones = np.array(xl.xlnscopy(list(np.ones((batchsize, 1))), xl.xlnsud)) lnsdelta_W1 = np.array(xl.xlnscopy(list(np.zeros(W1.shape)), xl.xlnsud)) lnsdelta_W2 = np.array(xl.xlnscopy(list(np.zeros(W2.shape)), xl.xlnsud)) elif main_params['type'] == 'xlnsv': lnsW1 = np.array(xl.xlnscopy(list(W1), xl.xlnsv, 6)) lnsW2 = np.array(xl.xlnscopy(list(W2), xl.xlnsv, 6)) lnsones = np.array(xl.xlnscopy(list(np.ones((batchsize, 1))), xl.xlnsv)) lnsdelta_W1 = np.array(xl.xlnscopy(list(np.zeros(W1.shape)), xl.xlnsv)) lnsdelta_W2 = np.array(xl.xlnscopy(list(np.zeros(W2.shape)), xl.xlnsv)) elif main_params['type'] == 'xlnsb': lnsW1 = np.array(xl.xlnscopy(list(W1), xl.xlnsb, 2**2**-6)) lnsW2 = np.array(xl.xlnscopy(list(W2), xl.xlnsb, 2**2**-6)) lnsones = np.array(xl.xlnscopy(list(np.ones((batchsize, 1))), xl.xlnsb, 2**2**-xl.xlnsF)) lnsdelta_W1 = np.array(xl.xlnscopy(list(np.zeros(W1.shape)), xl.xlnsb, 2**2**-xl.xlnsF)) lnsdelta_W2 = np.array(xl.xlnscopy(list(np.zeros(W2.shape)), xl.xlnsb, 2**2**-xl.xlnsF)) elif main_params['type'] == 'float': lnsW1 = np.array(list(W1)) lnsW2 = np.array(list(W2)) lnsones = np.array(list(np.ones((batchsize, 1)))) lnsdelta_W1 = np.array(list(np.zeros(W1.shape))) lnsdelta_W2 = np.array(list(np.zeros(W2.shape))) performance = {} performance['lnsacc_train'] = np.zeros(num_epoch) performance['lnsacc_val'] = np.zeros(num_epoch) start_time = time.process_time() # Training loop for epoch in range(num_epoch): print('At Epoch %d:' % (1 + epoch)) # Loop through training batches for mbatch in range(int(split / batchsize)): start = mbatch * batchsize x = np.array(x_train[start:(start + batchsize)]) y = np.array(y_train[start:(start + batchsize)]) # At this point, each x is already flattened (batchsize x 784) # Conversion based on type if main_params['type'] == 'xlnsnp': lnsx = xl.xlnsnp(np.array(xl.xlnscopy(np.array(x, dtype=np.float64)))) lnsy = xl.xlnsnp(np.array(xl.xlnscopy(np.array(y, dtype=np.float64)))) elif main_params['type'] == 'xlnsnpv': lnsx = xl.xlnsnpv(np.array(xl.xlnscopy(np.array(x, dtype=np.float64)))) lnsy = xl.xlnsnpv(np.array(xl.xlnscopy(np.array(y, dtype=np.float64)))) elif main_params['type'] == 'xlnsnpb': lnsx = xl.xlnsnpb(np.array(xl.xlnscopy(np.array(x, dtype=np.float64))), 2**2**-xl.xlnsF) lnsy = xl.xlnsnpb(np.array(xl.xlnscopy(np.array(y, dtype=np.float64))), 2**2**-xl.xlnsF) elif main_params['type'] == 'xlns': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64))) lnsy = np.array(xl.xlnscopy(np.array(y, dtype=np.float64))) elif main_params['type'] == 'xlnsud': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64), xl.xlnsud)) lnsy = np.array(xl.xlnscopy(np.array(y, dtype=np.float64), xl.xlnsud)) elif main_params['type'] == 'xlnsv': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64), xl.xlnsv)) lnsy = np.array(xl.xlnscopy(np.array(y, dtype=np.float64), xl.xlnsv)) elif main_params['type'] == 'xlnsb': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64), xl.xlnsv, 2**2**-xl.xlnsF)) lnsy = np.array(xl.xlnscopy(np.array(y, dtype=np.float64), xl.xlnsv, 2**2**-xl.xlnsF)) elif main_params['type'] == 'float': lnsx = np.array(x, dtype=np.float64) lnsy = np.array(y, dtype=np.float64) # Concatenate the bias "ones" with input features for the first layer lnss1 = xl.hstack((lnsones, lnsx)) @ lnsW1 lnsmask = (lnss1 > 0) + (leaking_coeff * (lnss1 < 0)) lnsa1 = lnss1 * lnsmask lnss2 = xl.hstack((lnsones, lnsa1)) @ lnsW2 lnsa2 = softmax(lnss2) lnsgrad_s2 = (lnsa2 - lnsy) / batchsize lnsgrad_a1 = lnsgrad_s2 @ xl.transpose(lnsW2[1:]) lnsdelta_W2 = xl.transpose(xl.hstack((lnsones, lnsa1))) * lnsgrad_s2 lnsgrad_s1 = lnsmask * lnsgrad_a1 lnsdelta_W1 = xl.transpose(xl.hstack((lnsones, lnsx))) * lnsgrad_s1 lnsW2 -= (lr * (lnsdelta_W2 + (_lambda * lnsW2))) lnsW1 -= (lr * (lnsdelta_W1 + (_lambda * lnsW1))) print('#= ', split, ' batch=', batchsize, ' lr=', lr) lnscorrect_count = 0 # Evaluate accuracy on training set for mbatch in range(int(split / batchsize)): start = mbatch * batchsize x = x_train[start:(start + batchsize)] y = y_train[start:(start + batchsize)] if main_params['type'] == 'xlnsnp': lnsx = xl.xlnsnp(np.array(xl.xlnscopy(np.array(x, dtype=np.float64)))) elif main_params['type'] == 'xlnsnpv': lnsx = xl.xlnsnpv(np.array(xl.xlnscopy(np.array(x, dtype=np.float64)))) elif main_params['type'] == 'xlnsnpb': lnsx = xl.xlnsnpb(np.array(xl.xlnscopy(np.array(x, dtype=np.float64))), 2**2**-xl.xlnsF) elif main_params['type'] == 'xlns': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64))) elif main_params['type'] == 'xlnsud': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64), xl.xlnsud)) elif main_params['type'] == 'xlnsv': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64), xl.xlnsv)) elif main_params['type'] == 'xlnsb': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64), xl.xlnsv, 2**2**-xl.xlnsF)) elif main_params['type'] == 'float': lnsx = np.array(x, dtype=np.float64) lnss1 = xl.hstack((lnsones, lnsx)) @ lnsW1 lnsmask = (lnss1 > 0) + (leaking_coeff * (lnss1 < 0)) lnsa1 = lnss1 * lnsmask lnss2 = xl.hstack((lnsones, lnsa1)) @ lnsW2 lnscorrect_count += np.sum(np.argmax(y, axis=1) == xl.argmax(lnss2, axis=1)) lnsaccuracy = lnscorrect_count / split print("train-set accuracy at epoch %d: %f" % (1 + epoch, lnsaccuracy)) performance['lnsacc_train'][epoch] = 100 * lnsaccuracy lnscorrect_count = 0 # Evaluate on the validation set for mbatch in range(int(split / batchsize)): start = mbatch * batchsize x = x_val[start:(start + batchsize)] y = y_val[start:(start + batchsize)] if main_params['type'] == 'xlnsnp': lnsx = xl.xlnsnp(np.array(xl.xlnscopy(np.array(x, dtype=np.float64)))) elif main_params['type'] == 'xlnsnpv': lnsx = xl.xlnsnpv(np.array(xl.xlnscopy(np.array(x, dtype=np.float64)))) elif main_params['type'] == 'xlnsnpb': lnsx = xl.xlnsnpb(np.array(xl.xlnscopy(np.array(x, dtype=np.float64))), 2**2**-xl.xlnsF) elif main_params['type'] == 'xlns': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64))) elif main_params['type'] == 'xlnsud': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64), xl.xlnsud)) elif main_params['type'] == 'xlnsv': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64), xl.xlnsv)) elif main_params['type'] == 'xlnsb': lnsx = np.array(xl.xlnscopy(np.array(x, dtype=np.float64), xl.xlnsv, 2**2**-xl.xlnsF)) elif main_params['type'] == 'float': lnsx = np.array(x, dtype=np.float64) lnss1 = xl.hstack((lnsones, lnsx)) @ lnsW1 lnsmask = (lnss1 > 0) + (leaking_coeff * (lnss1 < 0)) lnsa1 = lnss1 * lnsmask lnss2 = xl.hstack((lnsones, lnsa1)) @ lnsW2 lnscorrect_count += np.sum(np.argmax(y, axis=1) == xl.argmax(lnss2, axis=1)) lnsaccuracy = lnscorrect_count / split print("Val-set accuracy at epoch %d: %f" % (1 + epoch, lnsaccuracy)) performance['lnsacc_val'][epoch] = 100 * lnsaccuracy print("elapsed time=" + str(time.process_time() - start_time)) fig = plt.figure(figsize=(16, 9)) ax = fig.add_subplot(111) x_axis = range(1, 1 + performance['lnsacc_train'].size) ax.plot(x_axis, performance['lnsacc_train'], 'y') ax.plot(x_axis, performance['lnsacc_val'], 'm') ax.set_xlabel('Number of Epochs') ax.set_ylabel('Accuracy') plt.suptitle(main_params['type'] + ' ' + str(split) + ' Validation and Training MNIST Accuracies F=' + str(xl.xlnsF), fontsize=14) ax.legend(['train', 'validation']) plt.grid(which='both', axis='both', linestyle='-.') plt.savefig('genericaccuracy.png') plt.show() # Now, show predictions on a few test images num_examples = 5 # Number of test images to display selected_indices = np.arange(num_examples) # choose the first few images for demo x_sample = x_test[selected_indices] y_sample = y_test[selected_indices] # For prediction, create a bias vector matching the sample size ones_sample = np.ones((x_sample.shape[0], 1)) z1_sample = np.hstack((ones_sample, x_sample)) @ lnsW1 mask_sample = (z1_sample > 0) + (leaking_coeff * (z1_sample < 0)) a1_sample = z1_sample * mask_sample z2_sample = np.hstack((ones_sample, a1_sample)) @ lnsW2 pred_probs = softmax(z2_sample) predictions = np.argmax(pred_probs, axis=1) true_labels = np.argmax(y_sample, axis=1) # Plot each test image along with its prediction and true label plt.figure(figsize=(10, 2)) for i in range(num_examples): plt.subplot(1, num_examples, i + 1) # Reshape the flattened image back to 28x28 for display plt.imshow(x_sample[i].reshape(28, 28), cmap='gray') plt.title(f"Pred: {predictions[i]}\nTrue: {true_labels[i]}") plt.axis('off') plt.tight_layout() plt.show() if __name__ == '__main__': # In a Kaggle notebook, set parameters manually using a dictionary. main_params = { 'is_training': True, 'split': 50, 'learning_rate': 0.01, 'lambda': 0.000, 'minibatch_size': 1, 'num_epoch': 5, 'leaking_coeff': 0.0078125, 'type': 'float' } main(main_params)


Мен сізге MNIST цифрлық классификациясы үшін логарифмдік санау жүйесін (LNS) көп деңгейлі перцептронды (MLP) жүзеге асыратын осы код арқылы таныстырамын. Оны негізгі бөлімдерге бөлуге рұқсат етіңіз:


  1. Орнату және импорттау:
  • Код логарифмдік санау жүйесінің операциялары үшін xlns кітапханасын пайдаланады

  • Ол әртүрлі дәлдік пен өнімділік үшін бірнеше LNS нұсқаларын (xlnsnp, xlnsnpv, xlnsud, т.б.) ұсынады.

  • MNIST деректер жинағы Keras арқылы жүктеледі


  1. Негізгі функциялар:
 def softmax(inp): max_vals = inp.max(axis=1) max_vals = xl.reshape(max_vals, (xl.size(max_vals), 1)) u = xl.exp(inp - max_vals) v = u.sum(axis=1) v = v.reshape((xl.size(v), 1)) u = u / v return u

Бұл LNS операцияларына бейімделген сандық тұрақты softmax іске асыру.


  1. Желінің архитектурасы:
  • Кіріс қабаты: 784 нейрон (28x28 тегістелген MNIST кескіндері) + 1 қиғаштық = 785

  • Жасырын қабат: 100 нейрон + 1 қиғаштық = 101

  • Шығыс деңгейі: 10 нейрон (әр санға бір)


  1. Салмақты инициализациялау:
  • Салмақ файлдан («weightin.npz») жүктеледі немесе кездейсоқ түрде инициализацияланады

  • Кездейсоқ салмақтар орташа=0, std=0,1 болатын қалыпты үлестіруді пайдаланады

  • Әртүрлі LNS нұсқалары әртүрлі инициализация әдістерін қажет етеді (xlnsnp, xlnsnpv, т.б.)


  1. Жаттығу циклі:
 for epoch in range(num_epoch): for mbatch in range(int(split / batchsize)): # Forward pass lnss1 = xl.hstack((lnsones, lnsx)) @ lnsW1 lnsmask = (lnss1 > 0) + (leaking_coeff * (lnss1 < 0)) lnsa1 = lnss1 * lnsmask lnss2 = xl.hstack((lnsones, lnsa1)) @ lnsW2 lnsa2 = softmax(lnss2) # Backward pass lnsgrad_s2 = (lnsa2 - lnsy) / batchsize lnsgrad_a1 = lnsgrad_s2 @ xl.transpose(lnsW2[1:]) lnsdelta_W2 = xl.transpose(xl.hstack((lnsones, lnsa1))) * lnsgrad_s2 lnsgrad_s1 = lnsmask * lnsgrad_a1 lnsdelta_W1 = xl.transpose(xl.hstack((lnsones, lnsx))) * lnsgrad_s1


Тренингтің негізгі аспектілері:

  • Ағып кеткен ReLU белсендіруін пайдаланады (leaking_coeff арқылы басқарылады)

  • Стандартты кері таралуды жүзеге асырады, бірақ LNS операцияларымен

  • L2 реттеуді қамтиды (лямбда параметрі)

  • "lr" оқу жылдамдығымен градиентті төмендету арқылы салмақтарды жаңартады


  1. Бағалау:
  • Жаттығудың да, валидацияның дәлдігін де қадағалайды

  • Дәуірлер бойынша дәлдікті көрсететін оқу қисықтарының сызбалары

  • Сынақ кескіндеріндегі үлгі болжамдарын көрсетеді


  1. Гиперпараметрлер:
 main_params = { 'is_training': True, 'split': 50, 'learning_rate': 0.01, 'lambda': 0.000, 'minibatch_size': 1, 'num_epoch': 5, 'leaking_coeff': 0.0078125, 'type': 'float' }
  • Шағын топтаманың градиент түсуін пайдаланады (әдепкі пакет өлшемі = 1)

  • Валидация жиынын бөлу арқылы ерте тоқтатуды жүзеге асырады

  • Leaky ReLU коэффициенті 0,0078125 мәніне орнатылған


  1. Көрнекілігі:
  • Жаттығу және тексеру дәлдігін көрсететін сюжеттер жасайды
  • Болжамдар мен шынайы белгілермен үлгі сынақ кескіндерін көрсетеді
  • Дәлдік сызбасын "genericaccuracy.png" ретінде сақтайды


Мұндағы негізгі жаңалық - LNS арифметикасын қолдану, ол көбейтуді журнал доменіндегі толықтырулармен ауыстырады, бұл белгілі бір аппараттық іске асыру үшін жақсырақ есептеу тиімділігін ұсынады. Код әртүрлі дәлдік-өнімділік алмасуларына мүмкіндік беретін бірнеше LNS нұсқаларын қолдайды.

Негізгі өнімділікті салыстыру

Қалқымалы нүкте үлгісінің өнімділігі

 Training on device: cuda Epoch [1/5], Loss: 0.8540, Train Acc: 79.60%, Val Acc: 88.22% Epoch [2/5], Loss: 0.3917, Train Acc: 88.97%, Val Acc: 89.92% Epoch [3/5], Loss: 0.3380, Train Acc: 90.29%, Val Acc: 90.60% Epoch [4/5], Loss: 0.3104, Train Acc: 90.96%, Val Acc: 91.12% Epoch [5/5], Loss: 0.2901, Train Acc: 91.60%, Val Acc: 91.62% Training completed in 57.76 seconds. 

FP негізіндегі MLP моделінің болжамдары

FP негізіндегі MLP үлгісі үшін оқыту және тексеру қисығы


Логарифмдік санау жүйесінің моделінің өнімділігі

 At Epoch 1: train-set accuracy at epoch 1: 52.00% Val-set accuracy at epoch 1: 24.00% At Epoch 2: train-set accuracy at epoch 2: 74.00% Val-set accuracy at epoch 2: 40.00% At Epoch 3: train-set accuracy at epoch 3: 86.00% Val-set accuracy at epoch 3: 58.00% At Epoch 4: train-set accuracy at epoch 4: 94.00% Val-set accuracy at epoch 4: 70.00% At Epoch 5: train-set accuracy at epoch 5: 96.00% Val-set accuracy at epoch 5: 68.00% elapsed time = 0.35 seconds. 

LNS негізіндегі MLP моделінің болжамдары

LNS негізіндегі MLP үлгісі үшін оқыту және тексеру қисығы


FP және LNS: негізгі салыстырулар

Аспект

Қалқымалы нүкте (FP)

Логарифмдік санау жүйесі (LNS)

Жаттығу уақыты

57,76 с

0,35 с

Пойыздың дәлдігі

91,60%

96,00%

Val дәлдігі

91,62%

68,00%

Дәлдік

Жоғары

Төменгі (жақындау қателері)

Жад тиімділігі

Жоғарырақ пайдалану

Жадтың төменгі ізі

Көбейтуді өңдеу

Туынды көбейту

Қосуға негізделген жеңілдетулер

Қорытынды

Логарифмдік санау жүйесі (LNS) мен қалқымалы нүкте (FP) арифметикасының арасындағы айырмашылықтар нейрондық желілерге арналған аппараттық-бағдарламалық қамтамасыз етудің бірлескен дизайнындағы қызықты мысалды ұсынады. LNS белгілі бір салаларда айтарлықтай артықшылықтар ұсынады:

Жаттығу жылдамдығы

  • Журнал доменінде көбейтуді қосумен ауыстырады
  • Күрделі амалдарды қарапайым арифметикаға азайтады
  • Нейрондық желілерде матрицаны көбейту үшін әсіресе тиімді
  • Кейбір енгізулерде 2–3 есе жылдамдыққа қол жеткізуге болады

Жад артықшылықтары

  • Әдетте сандарды көрсету үшін азырақ бит қажет
  • Салмақтарды және белсендірулерді тиімдірек қыса алады
  • Жад өткізу қабілетіне қойылатын талаптарды азайтады
  • Жадқа қол жеткізу үшін аз қуат тұтыну


Дегенмен, дәлдік бойынша қиындықтар маңызды:

  • Кішігірім мәндерді жинақтау кезінде дәлдікті жоғалту
  • Нөлге жақын сандарды көрсетудің қиындығы
  • Градиенттік есептеулердегі потенциалдық тұрақсыздық
  • Гиперпараметрді мұқият реттеуді қажет етуі мүмкін

Болашақ бағыттары

Бірнеше перспективалы тәсілдер LNS қолдану мүмкіндігін арттыруы мүмкін:

1. Қабатқа арналған арифметика

  • Сезімтал қабаттар үшін FP пайдаланыңыз (соңғы жіктеу сияқты)
  • LNS есептеуді қажет ететін жасырын қабаттарда қолданыңыз
  • Сандық талаптарға негізделген динамикалық ауысу

2. Дәлдікке бейімделген есептеулер

  • Тұрақтылық үшін FP жаттығуын бастаңыз
  • Салмақтар жақындаған сайын LNS-ге біртіндеп ауысыңыз
  • Критикалық жолдарды жоғары дәлдікте ұстаңыз

3. Аппараттық құралдардың бірлескен дизайны

  • FP және LNS бірліктері бар теңшелетін үдеткіштер
  • Арифметикалық түрлер арасындағы ақылды жоспарлау
  • Әрбір пішім үшін арнайы жад иерархиялары

4. Алгоритмдік инновациялар

  • LNS үшін оңтайландырылған жаңа белсендіру функциялары
  • Тұрақтылықты сақтайтын модификацияланған оңтайландыру алгоритмдері
  • Гибридті сандарды көрсету

Потенциалды PyTorch қолдауы

LNS-ті терең оқыту құрылымдарына біріктіру үшін мыналарды зерттеуге болады:

1. Теңшелетін Autograd функциялары

  • LNS операцияларын теңшелетін автоградтық функциялар ретінде орындаңыз
  • Журнал доменінде градиентті есептеуді сақтаңыз
  • Жеделдету үшін тиімді CUDA ядроларын қамтамасыз етіңіз

2. Сан түрінің кеңейтімдері

  • Жергілікті LNS тензор түрлерін қосыңыз
  • Журнал доменінде негізгі операцияларды (*+, -, , / ) орындаңыз
  • Қалқымалы нүктеге/қайтадан түрлендіру утилиталарын қамтамасыз етіңіз

3. Қабат модификациялары

  • Жалпы қабаттардың LNS нұсқаларын жасау (Linear, Conv2d)
  • LNS есептеуі үшін кері өтулерді оңтайландыру
  • Аралас дәлдік жаттығуларын қолдау


Терең білім беру қауымдастығы бұл мүмкіндіктерді тиімдірек, төмен қуатты және жоғары жылдамдықты нейрондық желілерге мүмкіндік беретін негізгі құрылымдарға біріктіруден үлкен пайда көре алады.


Сандық дәлдік пен есептеу тиімділігі арасындағы тепе-теңдік туралы ойларыңыз қандай? LNS әсіресе пайдалы болуы мүмкін нақты пайдалану жағдайларын кездестірдіңіз бе?


Бұл туралы өз ойларыңызды айтыңыз.

Анықтамалар


[1] G. Alsuhli, et al., “Number Systems for Deep Neural Network Architectures: A Survey,” arXiv:2307.05035 , 2023 ж.

[2] М.Арнольд, Э.Честер және т.б., «Тек жуық кестесіз LNS ALU көмегімен нейрондық желілерді оқыту». Қолданбаларға арналған арнайы жүйелер, архитектуралар және процессорлар бойынша 31-ші халықаралық конференция, IEEE , 2020, 69–72 беттер. DOI

[3] О. Кошелева, т.б., «Логарифмдік санау жүйесі AI есептеулері үшін оңтайлы: эмпирикалық табыстың теориялық түсіндірмесі», қағаз

[4] Д.Мияшита және т.б., «Логарифмдік деректерді ұсынуды пайдаланатын конволюциондық нейрондық желілер», arXiv:1603.01025 , наурыз 2016 ж.

[5] J. Zhao et al., “LNS-Madam: Low-Precision Training in Logarifmic Number System in Multiplicative Weight Update,” IEEE Transactions on Computers , том. 71, жоқ. 12, 3179–3190 беттер, 2022 ж. желтоқсан. DOI