【问题标题】:How to save the coefficients for each optim iteration?如何保存每次优化迭代的系数?
【发布时间】:2018-09-28 09:20:37
【问题描述】:

此问题与Applying Cost Functions in R有关

我想知道如何保存为optim 的每次迭代生成的系数。 trace=TRUE 使我能够打印出每次迭代的系数,但如何保存它们?

示例代码:

set.seed(1)
X <- matrix(rnorm(1000), ncol=10) # some random data
Y <- sample(0:1, 100, replace=TRUE)

# Implement Sigmoid function
sigmoid <- function(z) {
  g <- 1/(1+exp(-z))
  return(g)
}

cost.glm <- function(theta,X) {
  m <- nrow(X)
  g <- sigmoid(X%*%theta)
  (1/m)*sum((-Y*log(g)) - ((1-Y)*log(1-g)))
}

X1 <- cbind(1, X)

df <- optim(par=rep(0,ncol(X1)), fn = cost.glm, method='CG',
            X=X1, control=list(trace=TRUE))

哪些输出:

 Conjugate gradients function minimizer
Method: Fletcher Reeves
tolerance used in gradient test=2.00089e-11
0 1 0.693147
parameters    0.00000    0.00000    0.00000    0.00000    0.00000    0.00000    0.00000 
   0.00000    0.00000    0.00000    0.00000 
 i> 1 3 0.662066
parameters   -0.01000   -0.01601   -0.06087    0.14891    0.04123    0.03835   -0.01898 
   0.00637    0.02954   -0.01423   -0.07544 
 i> 2 5 0.638548
parameters   -0.02366   -0.03733   -0.13803    0.32782    0.09034    0.08082   -0.03978 
   0.01226    0.07120   -0.02925   -0.16042 
 i> 3 7 0.630501
parameters   -0.03478   -0.05371   -0.19149    0.43890    0.11960    0.10236   -0.04935 
   0.01319    0.10648   -0.03565   -0.20408 
 i> 4 9 0.627570.......

而df不包含任何有关系数的信息,而只显示最终的系数和最终的成本:

 str(df)
List of 5
 $ par        : num [1:11] -0.0679 -0.1024 -0.2951 0.6162 0.124 ...
 $ value      : num 0.626
 $ counts     : Named int [1:2] 53 28
  ..- attr(*, "names")= chr [1:2] "function" "gradient"
 $ convergence: int 0
 $ message    : NULL

【问题讨论】:

    标签: r


    【解决方案1】:
    ## use `capture.output` to get raw output
    out <- capture.output(df <- optim(par=rep(0,ncol(X1)), fn = cost.glm, method='CG',
                                      X=X1, control=list(trace=TRUE)))
    ## lines that contain parameters
    start <- grep("parameters", out)
    param_line <- outer(seq_len(start[2] - start[1] - 1) - 1, start, "+")
    ## parameter message
    param_msg <- gsub("parameters", "", out[param_line])
    ## parameter matrix (a row per iteration)
    param <- matrix(scan(text = param_msg), ncol = length(df$par), byrow = TRUE)
    
    ## inspect output (rounded to 2-digits for compact display)
    
    head(round(param, 2))
    #       [,1]  [,2]  [,3] [,4] [,5] [,6]  [,7]  [,8] [,9] [,10] [,11]
    # [1,]  0.00  0.00  0.00 0.00 0.00 0.00  0.00  0.00 0.00  0.00  0.00
    # [2,] -0.01 -0.02 -0.06 0.15 0.04 0.04 -0.02  0.01 0.03 -0.01 -0.08
    # [3,] -0.02 -0.04 -0.14 0.33 0.09 0.08 -0.04  0.01 0.07 -0.03 -0.16
    # [4,] -0.03 -0.05 -0.19 0.44 0.12 0.10 -0.05  0.01 0.11 -0.04 -0.20
    # [5,] -0.04 -0.07 -0.23 0.51 0.14 0.11 -0.05  0.01 0.14 -0.04 -0.22
    # [6,] -0.05 -0.08 -0.25 0.55 0.14 0.12 -0.05  0.01 0.16 -0.04 -0.23
    
    tail(round(param, 2))
    #[23,] -0.07 -0.10 -0.30 0.62 0.12 0.13 -0.03 -0.01 0.21 -0.04 -0.21
    #[24,] -0.07 -0.10 -0.30 0.62 0.12 0.13 -0.03 -0.01 0.21 -0.04 -0.21
    #[25,] -0.07 -0.10 -0.30 0.62 0.12 0.13 -0.03 -0.01 0.21 -0.04 -0.21
    #[26,] -0.07 -0.10 -0.30 0.62 0.12 0.13 -0.03 -0.01 0.21 -0.04 -0.21
    #[27,] -0.07 -0.10 -0.30 0.62 0.12 0.13 -0.03 -0.01 0.21 -0.04 -0.21
    #[28,] -0.07 -0.10 -0.30 0.62 0.12 0.13 -0.03 -0.01 0.21 -0.04 -0.21
    
    ## one way to visualize the search steps
    matplot(param, type = "l", lty = 1, xlab = "iterations")
    

    【讨论】:

      【解决方案2】:

      因此,其他解决方案有效...但涉及解析跟踪内的响应。 这是一种让您直接访问对象的方法。 (并且在任何其他不允许您轻松显示文本跟踪的优化功能中都是通用的):

      (这是可行的,因为您可以从函数内部分配环境内部)

      编辑:每次运行 cost.glm 时都会添加另一行,而不仅仅是每次评估跟踪时。

      还添加了转换为其他解决方案使用的矩阵格式。

      set.seed(1)
      X <- matrix(rnorm(1000), ncol=10) # some random data
      Y <- sample(0:1, 100, replace=TRUE)
      
      
      # Implement Sigmoid function
      sigmoid <- function(z) {
        g <- 1/(1+exp(-z))
        return(g)
      }
      
      # Create environment to store output
      # We could also use .GlobalEnv
      params_env <- new.env()
      
      # Initialize parameters object
      params_env$optim_run <- list()
      
      cost.glm <- function(theta,X) {
        # Extend the list by 1 and insert theta inside the given environment
        # This can be done more efficiently by
        # extending several at a time, but that's easy to add.
        n <- length(params_env[['optim_run']])
        params_env[['optim_run']][[n + 1]] <- theta
      
        m <- nrow(X)
        g <- sigmoid(X%*%theta)
        (1/m)*sum((-Y*log(g)) - ((1-Y)*log(1-g)))
      }
      
      X1 <- cbind(1, X)
      
      df <- optim(par=rep(0,ncol(X1)), fn = cost.glm, method='CG',
                  X=X1, control=list(trace=TRUE))
      
      # View list of all param values
      print(params_env$optim_run)
      
      # Return as same format as other solution
      param <- do.call(rbind, params_env[['optim_run']])
      
      matplot(param, type = "l", lty = 1, xlab = "iterations")
      

      【讨论】:

      • 与其他解决方案相比,此输出相当混乱。为什么会有这么多重复?
      • 它只是作为一个列表输出。数据应与其他解决方案相同。如果您想以与以下相同的格式返回,可以执行do.call(rbind, params_env[['optim_run']])
      • 如果数据不同,则表示每次运行 cost.glm 时都没有返回其他解决方案的跟踪输出。这将是其他解决方案的潜在问题
      • 不同之处在于(取决于使用的方法)目标函数可以由optim 每次迭代多次评估。当没有提供导数函数时,这种情况最常见(但不是唯一),并且在非常接近当前迭代的点处多次评估目标,以便在多个方向上找到斜率(偏导数)。因此,该方法每次迭代都会为 optim 完成的每个客观评估返回许多值,因为它决定下一次迭代的去向...
      • @dww 是的,这是有道理的。我倾向于查看每次迭代的成本函数的每次评估,因为成本函数的迭代比算法的迭代更好地衡量性能。我会将梯度搜索视为搜索的一部分......但取决于用例
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-11
      • 2018-02-13
      • 1970-01-01
      • 2019-06-20
      • 1970-01-01
      • 1970-01-01
      • 2017-11-07
      相关资源
      最近更新 更多