Jusqu’présentement, total torch les cas d’usage lequel nous-même avons chicané ici ont été en expérimentation cavé. Mais, sa exercice de distinction animal est rentable comme d’singulières domaines. Un prototype poignant est l’taylorisation binaire : nous-même pouvons apposer torch verso augurer le valeur-limite d’une exercice.

En cataclysme, la rabaissement de la exercice est entièrement ce qui se accompli comme la brigade d’un chaîne de neurones. Uniquement là, la exercice en tracas est couramment infiniment démesurément pénible verso même découvrir augurer ses minima analytiquement. L’taylorisation binaire vise à échafauder les outils verso préconiser cette imprévu. Vers ceci, purement, il quartier de épreuves infiniment moins ardemment composées. Au angle de ceci, ils sont fabriqués livre verso placer des défis uniques.

Ce ticket est une lauréate préambule à l’taylorisation binaire puis torch. Les capitaux points à obstruer sont l’nature et l’remplaçant de son optimiseur L-BFGS, en conséquence que l’effet de l’agencement de L-BFGS puis la soigné de arête. Alors accessoire ondulant, nous-même montrons un prototype d’taylorisation astreinte, où une astreinte est appliquée via une exercice de condamnation quadrilatère.

Vers s’animer, on cataclysme un évitement en minimisant une exercice “nous” en n’utilisant que des tenseurs. Ceci s’avérera intelligent mieux tard, car le algorithme quantité sera sans cesse le même. Intégraux les changements seront liés à l’concentration de optimizers et à elles moyen.

Infériorisation des épreuves, arrivé DYI

Vers référer à hein on peut soulager une exercice “livre”, essayons la exercice métaphorique de Rosenbrock. C’est une exercice à double variables :

( f(x_1, x_2) = (a – x_1)^2 + b * (x_2 – x_1^2)^2 )

puis (un) et (b) paramètres configurables ordinairement définis sur 1 et 5, respectivement.

En R :

library(torch)

a <- 1
b <- 5

rosenbrock <- function(x) {
  x1 <- x(1)
  x2 <- x(2)
  (a - x1)^2 + b * (x2 - x1^2)^2
}

Son valeur-limite se situe en (1,1), à l’viscère d’une défilé restreinte pleine de falaises vertigineuses :


Fonction de Rosenbrock.

Forme 1 : Caricature de Rosenbrock.

À nous rêve et à nous tactique sont les suivants.

On veut augurer les maîtrises (x_1) et (x_2) verso lépreux la exercice affecté son valeur-limite. Quelques-uns endettons arriver chaque quartier; et d’où que ceci nous-même amène sur le sinuosité, nous-même suivons le pas du tout du gradient “moyennant le bas”, gamin comme des régions de sang-froid de exercice à la suite mieux aérienne.

Matériellement, à tout répétition, on prend le leçon ((x1,x2)) porté, calculez la sang-froid de la exercice en conséquence que le gradient, et soustrayez une tronçon de celui-là verso commencer à un récent ((x1,x2)) quémandeur. Ce algorithme se encourage jusqu’à ce que nous-même atteignions le valeur-limite – le gradient est nul – ou que l’raffermissement bien inférieure à un entrée coloré.

Voilà le glossaire associatif. Sinon faculté distincte, nous-même commençons à (-1,1) . Le pourcentage d’expérimentation (la tronçon du gradient à déconseiller) nécessite différents expérimentations. (Essayez 0,1 et 0,001 verso référer à son effet.)

num_iterations <- 1000

# tronçon of the gradient to subtract 
lr <- 0.01

# function input (x1,x2)
# this is the tensor w.r.t. which we'll have torch compute the gradient
x_star <- torch_tensor(c(-1, 1), requires_grad = TRUE)

for (i in 1:num_iterations) {

  if (i %% 100 == 0) cat("Iteration: ", i, "n")

  # call function
  value <- rosenbrock(x_star)
  if (i %% 100 == 0) cat("Value is: ", as.numeric(value), "n")

  # compute gradient of value w.r.t. params
  value$backward()
  if (i %% 100 == 0) cat("Gradient is: ", as.matrix(x_star$grad), "nn")

  # manual update
  with_no_grad({
    x_star$sub_(lr * x_star$grad)
    x_star$grad$zero_()
  })
}
Iteration:  100 
Value is:  0.3502924 
Gradient is:  -0.667685 -0.5771312 

Iteration:  200 
Value is:  0.07398106 
Gradient is:  -0.1603189 -0.2532476 

...
...

Iteration:  900 
Value is:  0.0001532408 
Gradient is:  -0.004811743 -0.009894371 

Iteration:  1000 
Value is:  6.962555e-05 
Gradient is:  -0.003222887 -0.006653666 

Privilège que ceci fonctionne, ceci sert directement à éclairer le parangon. Plus torch fournissant un tas d’algorithmes d’taylorisation éprouvés, nous-même n’avons pas attrait de disposer artisanalement le quémandeur (mathbf{x}) maîtrises.

Infériorisation des épreuves puis torch optimiseurs

Au angle de ceci, nous-même laissons un torch optimiseur affermir à lunette le quémandeur (mathbf{x}) verso nous-même. Journellement, à nous préalable esquisse est Adam.

Adam

Plus Adam, l’taylorisation se déroule infiniment mieux compendieusement. À tangible prétexte, sélectionner un bon bascule d’expérimentation sans cesse requête une observation non infime. (Essayez le pourcentage d’expérimentation par absence, 0,001, à cartouche de relation.)

num_iterations <- 100

x_star <- torch_tensor(c(-1, 1), requires_grad = TRUE)

lr <- 1
optimizer <- optim_adam(x_star, lr)

for (i in 1:num_iterations) {
  
  if (i %% 10 == 0) cat("Iteration: ", i, "n")
  
  optimizer$zero_grad()
  value <- rosenbrock(x_star)
  if (i %% 10 == 0) cat("Value is: ", as.numeric(value), "n")
  
  value$backward()
  optimizer$step()
  
  if (i %% 10 == 0) cat("Gradient is: ", as.matrix(x_star$grad), "nn")
  
}
Iteration:  10 
Value is:  0.8559565 
Gradient is:  -1.732036 -0.5898831 

Iteration:  20 
Value is:  0.1282992 
Gradient is:  -3.22681 1.577383 

...
...

Iteration:  90 
Value is:  4.003079e-05 
Gradient is:  -0.05383469 0.02346456 

Iteration:  100 
Value is:  6.937736e-05 
Gradient is:  -0.003240437 -0.006630421 

Il nous-même a fallu une centaine d’itérations verso commencer à une sang-froid décente. C’est infiniment mieux alerte que l’arrivé manuelle plus haut, toutefois c’est supposé que même infiniment. Favorablement, d’singulières améliorations sont possibles.

L-BFGS

Entre les copieux torch des optimiseurs volontiers utilisés en deep learning (Adam, AdamW, RMSprop…), il existe un « challenger », empressé mieux intime en taylorisation binaire traditionnel que comme l’blanc des réseaux de neurones : L-BFGS, différemment Limited-memory BFGS, un optimiseur montré réalisation de l’processus d’taylorisation Broyden-Fletcher-Goldfarb-Shanno (BFGS).

BFGS est probablement le mieux amplement appliqué chez les algorithmes d’taylorisation du accolé billet dits quasi-Newton. Défavorablement à la maison des algorithmes du préalable billet qui, verso juger d’une patronage de affalement, n’utilisent que les informations de gradient, les algorithmes du accolé billet prennent en prudent en mieux les informations de cavité. À cette fin, les méthodes exactes de Newton calculent en cataclysme le Hessian (une excision chère), donc que les méthodes Approximativement-Newton évitent ce débours et ont de préférence proclamation à une évaluation recommencée.

En ladre les contours de la exercice de Rosenbrock, puis sa défilé restreinte et prolongée, il n’est pas ardu d’découvrir que les informations de cavité pourraient agissant une contraire. Et, même vous-même le verrez comme une minute, c’est directement le cas. Ci-devant purement, une réflexion sur le glossaire. Tandis de l’usage de L-BFGS, il est tronc d’fermer à la jour l’diplomatie de exercice et l’comparaison du gradient comme une crampon (calc_loss(), comme l’déraciné ci-après), verso qu’ils puissent participer appelés discordantes jour par répétition. Toi-même pouvez vous-même conduire que la crampon est, en cataclysme, initiation à discordantes reprises, en inspectant la attaque vigoureuse de cet déraciné de glossaire :

num_iterations <- 3

x_star <- torch_tensor(c(-1, 1), requires_grad = TRUE)

optimizer <- optim_lbfgs(x_star)

calc_loss <- function() {

  optimizer$zero_grad()

  value <- rosenbrock(x_star)
  cat("Value is: ", as.numeric(value), "n")

  value$backward()
  cat("Gradient is: ", as.matrix(x_star$grad), "nn")
  value

}

for (i in 1:num_iterations) {
  cat("Iteration: ", i, "n")
  optimizer$step(calc_loss)
}
Iteration:  1 
Value is:  4 
Gradient is:  -4 0 

Value is:  6 
Gradient is:  -2 10 

...
...

Value is:  0.04880721 
Gradient is:  -0.262119 -0.1132655 

Value is:  0.0302862 
Gradient is:  1.293824 -0.7403332 

Iteration:  2 
Value is:  0.01697086 
Gradient is:  0.3468466 -0.3173429 

Value is:  0.01124081 
Gradient is:  0.2420997 -0.2347881 

...
...

Value is:  1.111701e-09 
Gradient is:  0.0002865837 -0.0001251698 

Value is:  4.547474e-12 
Gradient is:  -1.907349e-05 9.536743e-06 

Iteration:  3 
Value is:  4.547474e-12 
Gradient is:  -1.907349e-05 9.536743e-06 

Même si nous-même avons réalisé l’processus contre triade itérations, la sang-froid optimale est directement chiquenaude derrière double. Étant quel nombre ceci a empressé fonctionné, nous-même essayons L-BFGS sur une exercice mieux ardu, nommée fleuretteverso des raisons modérément évidentes.

(Surtout) mieux de rigolade puis L-BFGS

Voilà la fleurette exercice. Rigoureusement, son valeur-limite est limitrophe de (0,0)toutefois techniquement la exercice elle est indéfinie à (0,0)depuis le atan2 appliqué comme la exercice n’y est pas achevé.

a <- 1
b <- 1
c <- 4

flower <- function(x) {
  a * torch_norm(x) + b * torch_sin(c * torch_atan2(x(2), x(1)))
}

Fonction fleur.

Forme 2 : Caricature fleurette.

Quelques-uns exécutons le même glossaire que plus haut, à décamper de (20,20) ce étape.

num_iterations <- 3

x_star <- torch_tensor(c(20, 0), requires_grad = TRUE)

optimizer <- optim_lbfgs(x_star)

calc_loss <- function() {

  optimizer$zero_grad()

  value <- flower(x_star)
  cat("Value is: ", as.numeric(value), "n")

  value$backward()
  cat("Gradient is: ", as.matrix(x_star$grad), "n")
  
  cat("X is: ", as.matrix(x_star), "nn")
  
  value

}

for (i in 1:num_iterations) {
  cat("Iteration: ", i, "n")
  optimizer$step(calc_loss)
}
Iteration:  1 
Value is:  28.28427 
Gradient is:  0.8071069 0.6071068 
X is:  20 20 

...
...

Value is:  19.33546 
Gradient is:  0.8100872 0.6188223 
X is:  12.957 14.68274 

...
...

Value is:  18.29546 
Gradient is:  0.8096464 0.622064 
X is:  12.14691 14.06392 

...
...

Value is:  9.853705 
Gradient is:  0.7546976 0.7025688 
X is:  5.763702 8.895616 

Value is:  2635.866 
Gradient is:  -0.7407354 -0.6717985 
X is:  -1949.697 -1773.551 

Iteration:  2 
Value is:  1333.113 
Gradient is:  -0.7413024 -0.6711776 
X is:  -985.4553 -897.5367 

Value is:  30.16862 
Gradient is:  -0.7903821 -0.6266789 
X is:  -21.02814 -21.72296 

Value is:  1281.39 
Gradient is:  0.7544561 0.6563575 
X is:  964.0121 843.7817 

Value is:  628.1306 
Gradient is:  0.7616636 0.6480014 
X is:  475.7051 409.7372 

Value is:  4965690 
Gradient is:  -0.7493951 -0.662123 
X is:  -3721262 -3287901 

Value is:  2482306 
Gradient is:  -0.7503822 -0.6610042 
X is:  -1862675 -1640817 

Value is:  8.61863e+11 
Gradient is:  0.7486113 0.6630091 
X is:  645200412672 571423064064 

Value is:  430929412096 
Gradient is:  0.7487153 0.6628917 
X is:  322643460096 285659529216 

Value is:  Inf 
Gradient is:  0 0 
X is:  -2.826342e+19 -2.503904e+19 

Iteration:  3 
Value is:  Inf 
Gradient is:  0 0 
X is:  -2.826342e+19 -2.503904e+19 

Ceci a moins empressé conquis. Originellement, la galvaudage diminue empressé, toutefois incessamment, l’évaluation dépasse copieusement et continue de recommencer dans l’blanc pas du tout et ferme verso sans cesse.

Favorablement, nous-même pouvons agissant chaque objet.

Approprié isolément, ce qu’une formule Approximativement-Newton même L-BFGS cataclysme, c’est traiter la meilleure patronage de affalement. Mais, même nous-même venons de le référer à, une jolie direction ne suffit pas. Plus la exercice fleurette, où que nous-même soyons, le sentier maximum mène au glas si nous-même y restons modérément beaucoup. Tel quel, nous-même avons attrait d’un processus qui considéré précisément non uniquement où exposer, toutefois de même jusqu’où.

Vers cette faculté, les implémentations L-BFGS intègrent éternellement soigné de arêtec’est-à-dire un choeur de menstruel indiquant si une grandeur de pas proposée est jolie ou doit participer améliorée.

Précisément, torchL’optimiseur L-BFGS de implémente les particularité de Strong Wolfe. Quelques-uns réexécutons le glossaire plus haut, en forain uniquement double niveaux. Le mieux insolent, icelui où l’optimiseur est instancié :

optimizer <- optim_lbfgs(x_star, line_search_fn = "strong_wolfe")

Et secundo, cette jour, j’ai notoire qu’derrière la arbitre répétition, la galvaudage continuait de abaisser contre un intelligible étape, lorsque je l’ai laissé jouer contre cinq itérations. Voilà la attaque :

Iteration:  1 
...
...

Value is:  -0.8838741 
Gradient is:  3.742207 7.521572 
X is:  0.09035123 -0.03220009 

Value is:  -0.928809 
Gradient is:  1.464702 0.9466625 
X is:  0.06564617 -0.026706 

Iteration:  2 
...
...

Value is:  -0.9991404 
Gradient is:  39.28394 93.40318 
X is:  0.0006493925 -0.0002656128 

Value is:  -0.9992246 
Gradient is:  6.372203 12.79636 
X is:  0.0007130796 -0.0002947929 

Iteration:  3 
...
...

Value is:  -0.9997789 
Gradient is:  3.565234 5.995832 
X is:  0.0002042478 -8.457939e-05 

Value is:  -0.9998025 
Gradient is:  -4.614189 -13.74602 
X is:  0.0001822711 -7.553725e-05 

Iteration:  4 
...
...

Value is:  -0.9999917 
Gradient is:  -382.3041 -921.4625 
X is:  -6.320081e-06 2.614706e-06 

Value is:  -0.9999923 
Gradient is:  -134.0946 -321.2681 
X is:  -6.921942e-06 2.865841e-06 

Iteration:  5 
...
...

Value is:  -0.9999999 
Gradient is:  -3446.911 -8320.007 
X is:  -7.267168e-08 3.009783e-08 

Value is:  -0.9999999 
Gradient is:  -3419.361 -8253.501 
X is:  -7.404627e-08 3.066708e-08 

Ce n’est pas mieux idéal, toutefois infiniment davantage.

Bref, allons un peu mieux ailleurs. Pouvons-nous apposer torch verso une taylorisation astreinte ?

Confirmation quadrilatère verso taylorisation astreinte

En taylorisation astreinte, on excavation sans cesse un valeur-limite, toutefois ce valeur-limite ne peut pas percher n’importe où : sa positionnement doit farcir un intelligible presse de particularité supplémentaires. Entre le galimatias de l’taylorisation, il doit participer imaginable.

Vers éclairer, nous-même restons puis la exercice fleurette, toutefois ajoutons une astreinte : (mathbf{x}) doit se circonscrire à l’attitude d’un voisinage de éclair (ouvert(2)), centré à l’entrée. Franchement, ceci fixe la astreinte d’particularité

( 2 – {x_1}^2 – {x_2}^2 <= 0 )

Un accommodement de soulager fleurette et nonobstant, en même étape, respecter la astreinte, c’est apposer une exercice de condamnation. Plus les méthodes de condamnation, la sang-froid à soulager est la facture de double choses : la attaque de la exercice victime et une condamnation reflétant une attaque potentielle de la astreinte. Manutention d’un quadrilatère mornepar prototype, entraîne l’adjonction d’un nombreux du ouvert de la attaque de la exercice de astreinte :

# x^2 + y^2 >= 2
# 2 - x^2 - y^2 <= 0
constraint <- function(x) 2 - torch_square(torch_norm(x))

# quadratic penalty
penalty <- function(x) torch_square(torch_max(constraint(x), other = 0))

A priori, nous-même ne pouvons pas érudition quel doit participer la épaisseur de ce nombreux verso assommer la astreinte. Par logique, l’taylorisation se déroule de soigné recommencée. On commence puis un nourrisson engendrant, (1)disons, et augmentez-le aussi que la astreinte est sans cesse violée :

penalty_method <- function(f, p, x, k_max, rho = 1, gamma = 2, num_iterations = 1) {

  for (k in 1:k_max) {
    cat("Starting step: ", k, ", rho = ", rho, "n")

    minimize(f, p, x, rho, num_iterations)

    cat("Value: ",  as.numeric(f(x)), "n")
    cat("X: ",  as.matrix(x), "n")
    
    current_penalty <- as.numeric(p(x))
    cat("Penalty: ", current_penalty, "n")
    if (current_penalty == 0) écart
    
    rho <- rho * gamma
  }

}

minimize()évoqué de penalty_method()suit la ergotage machinale, toutefois céans il minimise la facture des sorties de la exercice de condamnation victime et pondérée :

minimize <- function(f, p, x, rho, num_iterations) {

  calc_loss <- function() {
    optimizer$zero_grad()
    value <- f(x) + rho * p(x)
    value$backward()
    value
  }

  for (i in 1:num_iterations) {
    cat("Iteration: ", i, "n")
    optimizer$step(calc_loss)
  }

}

Cette jour, nous-même partons d’une sang-froid de galvaudage victime chancelant, toutefois inaccessible. Plus mieux une différent évolution du L-BFGS par absence (à érudition, une évaporation de la libéralisme), nous-même voyons l’processus tirer puis protection derrière vingt-deux itérations, au porté (0.5411692,1.306563).

x_star <- torch_tensor(c(0.5, 0.5), requires_grad = TRUE)

optimizer <- optim_lbfgs(x_star, line_search_fn = "strong_wolfe", tolerance_change = 1e-20)

penalty_method(flower, penalty, x_star, k_max = 30)
Starting step:  1 , rho =  1 
Iteration:  1 
Value:  0.3469974 
X:  0.5154735 1.244463 
Penalty:  0.03444662 

Starting step:  2 , rho =  2 
Iteration:  1 
Value:  0.3818618 
X:  0.5288152 1.276674 
Penalty:  0.008182613 

Starting step:  3 , rho =  4 
Iteration:  1 
Value:  0.3983252 
X:  0.5351116 1.291886 
Penalty:  0.001996888 

...
...

Starting step:  20 , rho =  524288 
Iteration:  1 
Value:  0.4142133 
X:  0.5411959 1.306563 
Penalty:  3.552714e-13 

Starting step:  21 , rho =  1048576 
Iteration:  1 
Value:  0.4142134 
X:  0.5411956 1.306563 
Penalty:  1.278977e-13 

Starting step:  22 , rho =  2097152 
Iteration:  1 
Value:  0.4142135 
X:  0.5411962 1.306563 
Penalty:  0 

Issue

En appréciation, nous-même avons eu une lauréate appréciation de l’valeur de torchL’optimiseur L-BFGS de , en inusité lorsqu’il est appliqué puis la soigné de arête Strong-Wolfe. En cataclysme, comme l’taylorisation binaire – par dégoût à l’expérimentation en abîme, où la presse de appréciation est infiniment mieux un impasse – il n’y a pour ainsi dire en aucun cas de faculté de pas apposer L-BFGS puis soigné de arête.

Quelques-uns avons puis conjecturé hein style une taylorisation astreinte, une tâche qui se assuré comme de nombreuses applications du monde certain. À cet scrupule, cet feuilleton ressemble infiniment mieux à un immersion qu’à un check-up. Il y a infiniment à parcourir, de l’guenille commun de la formule – supposé que le L-BFGS est-il empressé synonyme à un impasse ? – via l’valeur de appréciation à l’congruence à hétérogènes liquide de réseaux de neurones. Futile de prétexte que si ceci vous-même inspire à engager vos propres expériences, et/ou si vous-même utilisez L-BFGS comme vos propres projets, nous-même serions ravis d’cousiner vos documents !

Remerciement d’disposer lu!

accolé

Dictionnaire de inscription de la exercice Rosenbrock

library(tidyverse)

a <- 1
b <- 5

rosenbrock <- function(x) {
  x1 <- x(1)
  x2 <- x(2)
  (a - x1)^2 + b * (x2 - x1^2)^2
}

df <- expand_grid(x1 = seq(-2, 2, by = 0.01), x2 = seq(-2, 2, by = 0.01)) %>%
  rowwise() %>%
  mutate(x3 = rosenbrock(c(x1, x2))) %>%
  ungroup()

ggplot(data = df,
       aes(x = x1,
           y = x2,
           z = x3)) +
  geom_contour_filled(breaks = as.numeric(torch_logspace(-3, 3, steps = 50)),
                      spectacle.legend = FALSE) +
  theme_minimal() +
  scale_fill_viridis_d(patronage = -1) +
  theme(configuration.pourcentage = 1)

Dictionnaire de inscription de la exercice Flower

a <- 1
b <- 1
c <- 4

flower <- function(x) {
  a * torch_norm(x) + b * torch_sin(c * torch_atan2(x(2), x(1)))
}

df <- expand_grid(x = seq(-3, 3, by = 0.05), y = seq(-3, 3, by = 0.05)) %>%
  rowwise() %>%
  mutate(z = flower(torch_tensor(c(x, y))) %>% as.numeric()) %>%
  ungroup()

ggplot(data = df,
       aes(x = x,
           y = y,
           z = z)) +
  geom_contour_filled(spectacle.legend = FALSE) +
  theme_minimal() +
  scale_fill_viridis_d(patronage = -1) +
  theme(configuration.pourcentage = 1)

Peinture de Michael Trimble sur Unsplash

By nsmaat