Exemplo n.º 1
0
    def __init__(self,
                 main_dir=None,
                 CaseStudy=0,
                 seq=3,
                 ndraw=10000,
                 thin=1,
                 nCR=3,
                 DEpairs=3,
                 parallelUpdate=0.9,
                 pCR=True,
                 k=10,
                 pJumpRate_one=0.2,
                 steps=100,
                 savemodout=False,
                 saveout=True,
                 save_tmp_out=True,
                 Prior='LHS',
                 DoParallel=True,
                 eps=5e-2,
                 BoundHandling='Reflect',
                 lik_sigma_est=False,
                 parallel_jobs=4,
                 jr_scale=1.0,
                 rng_seed=123):

        self.CaseStudy = CaseStudy
        MCMCPar.seq = seq
        MCMCPar.ndraw = ndraw
        MCMCPar.thin = thin
        MCMCPar.nCR = nCR
        MCMCPar.DEpairs = DEpairs
        MCMCPar.parallelUpdate = parallelUpdate
        MCMCPar.Do_pCR = pCR
        MCMCPar.k = k
        MCMCPar.pJumpRate_one = pJumpRate_one
        MCMCPar.steps = steps
        MCMCPar.savemodout = savemodout
        MCMCPar.saveout = saveout
        MCMCPar.save_tmp_out = save_tmp_out
        MCMCPar.Prior = Prior
        MCMCPar.DoParallel = DoParallel
        MCMCPar.eps = eps
        MCMCPar.BoundHandling = BoundHandling
        MCMCPar.jr_scale = jr_scale
        MCMCPar.lik_sigma_est = lik_sigma_est
        Extra.n_jobs = parallel_jobs
        Extra.main_dir = main_dir
        np.random.seed(rng_seed)
        MCMCPar.rng_seed = rng_seed

        if self.CaseStudy == 2:

            ModelName = 'linear_gpr_tomo'
            MCMCPar.lik = 2

            MCMCPar.savemodout = False
            MCMCPar.lik_sigma_est = False

            MCMCPar.lb = np.ones((1, 15)) * -1
            MCMCPar.ub = np.ones((1, 15))
            MCMCPar.n = MCMCPar.ub.shape[1]

            # Set forward model stuff:
            from tomokernel_straight import tomokernel_straight_2D

            nx = 60  # Here x is the horizontal axis (number of columns) and not the number of rows
            ny = 125  # Here y is the vertical axis (number of rows) and not the number of columns

            # The x-axis is varying the fastest
            x = np.arange(0, (nx / 10) + 0.1, 0.1)
            y = np.arange(0, (ny / 10) + 0.1, 0.1)
            sourcex = 0.01
            sourcez = np.arange(0.5, ny / 10, 0.5)
            receiverx = nx / 10 - 0.01
            receiverz = np.arange(0.5, ny / 10, 0.5)
            nsource = len(sourcez)
            nreceiver = len(receiverz)
            ndata = nsource * nreceiver
            data = np.zeros((ndata, 4))
            # Calculate acquisition geometry (multiple-offset gather)
            for jj in range(0, nsource):
                for ii in range(0, nreceiver):
                    data[(jj) * nreceiver + ii, :] = np.array(
                        [sourcex, sourcez[jj], receiverx, receiverz[ii]])
            # Calculate forward modeling kernel (from Matlab code by Dr. James Irving, UNIL)
            G = tomokernel_straight_2D(
                data, x,
                y)  # Distance of ray-segment in each cell for each ray
            Extra.G = np.array(G.todense())

            # DNN stuff
            DNN = AttrDict()
            DNN.nx = nx
            DNN.ny = ny
            DNN.zx = 5
            DNN.zy = 3
            DNN.nc = 1
            DNN.nz = 1
            DNN.depth = 5
            DNN.threshold = True
            DNN.filtering = False
            DNN.cuda = True

            DNN.gpath = Extra.main_dir + '/generation/netG.pth'

            from generator import Generator as Generator

            DNN.npx = (DNN.zx - 1) * 2**DNN.depth + 1
            DNN.npy = (DNN.zy - 1) * 2**DNN.depth + 1
            DNN.netG = Generator(cuda=DNN.cuda, gpath=DNN.gpath)
            for param in DNN.netG.parameters():
                param.requires_grad = False
            DNN.netG.eval()
            if DNN.cuda:
                DNN.netG.cuda()
            self.DNN = DNN

            # Load measurements
            file_name = 'measurements.pkl'
            Measurement.Sigma = 1  # Measurement error is 1 ns
            with open(file_name, 'rb') as fin:
                tmp = pickle.load(fin)
                Extra.z_true = tmp['z_true']
                if DNN.threshold:
                    Extra.m_true = tmp['m_true']
                    Measurement.MeasData = tmp['d']
                else:
                    Extra.m_true = tmp['m_true_cont']
                    Measurement.MeasData = tmp['d_cont']
                del tmp
            Measurement.N = len(Measurement.MeasData)

        elif self.CaseStudy == 1:
            # A theoretical 10-dimensional bimodal distribution made of 2 Gaussians
            # (example 3 in Matlab DREAMzs code)
            self.ndim = 10
            MCMCPar.n = self.ndim
            MCMCPar.Prior = 'COV'
            MCMCPar.lb = np.zeros((1, MCMCPar.n)) - 100
            MCMCPar.ub = np.zeros((1, MCMCPar.n)) + 100
            MCMCPar.BoundHandling = None
            Measurement.N = 1
            ModelName = 'theoretical_case_bimodal_mvn'
            MCMCPar.lik = 1
            Extra.cov1 = np.eye(MCMCPar.n)
            Extra.cov2 = np.eye(MCMCPar.n)
            Extra.mu1 = np.zeros((MCMCPar.n)) - 5
            Extra.mu2 = np.zeros((MCMCPar.n)) + 5

        elif self.CaseStudy == 0:
            # A theoretical multivariate normal distribution with 100 correlated dimensions
            # (example 2 in Matlab DREAM code)
            self.ndim = 100
            MCMCPar.n = self.ndim
            MCMCPar.Prior = 'LHS'
            MCMCPar.lb = np.zeros((1, MCMCPar.n)) - 5
            MCMCPar.ub = np.zeros((1, MCMCPar.n)) + 15
            MCMCPar.BoundHandling = 'Reflect'

            Measurement.N = 1
            ModelName = 'theoretical_case_mvn'
            MCMCPar.lik = 0

            A = 0.5 * np.eye(MCMCPar.n) + 0.5 * np.ones(MCMCPar.n)
            cov = np.zeros((MCMCPar.n, MCMCPar.n))
            # Rescale to variance-covariance matrix of interest
            for i in range(0, MCMCPar.n):
                for j in range(0, MCMCPar.n):
                    cov[i, j] = A[i, j] * np.sqrt((i + 1) * (j + 1))
            Extra.C = cov
            Extra.invC = np.linalg.inv(cov)

        else:  # This should not happen and is thus probably not needed
            self.ndim = 1
            MCMCPar.n = self.ndim
            MCMCPar.lb = np.zeros((1, MCMCPar.n))
            MCMCPar.ub = np.zeros((1, MCMCPar.n)) + 1
            MCMCPar.BoundHandling = None
            Measurement.N = 1
            ModelName = None
            MCMCPar.lik = 1

        MCMCPar.m0 = 10 * MCMCPar.n

        self.MCMCPar = MCMCPar
        self.Measurement = Measurement
        self.Extra = Extra
        self.ModelName = ModelName
def run_inv_gn(niter, gpath, nc, nz, zx, zy, cuda, model_index, noise_index,
               threshold, filtering, FDCalcJ, invCe, maxit, it_stop, rmse_stop,
               Prior, D, delta_z, labda, labda_max, labda_min, labdaUpdate,
               VaryAlfa, AdaptJump, Regularization, mv, test_type, alfa_min,
               alfa_f):

    # Load true model and measurement data
    model_path = './true_model_' + str(model_index) + '_noise_' + str(
        noise_index)
    with open(model_path + '.pkl', 'rb') as fin:
        tmp = pickle.load(fin)

        if threshold:
            #z_true=tmp['z_true']
            model_true = tmp['m_true']
            d = tmp['d']
        else:
            model_true = tmp['m_true_cont']  #125 x 60 in [0,1]
            d = tmp['d_cont']

    # forward setup
    from tomokernel_straight import tomokernel_straight_2D

    nx = 60  # Here x is the horizontal axis (number of columns) and not the number of rows
    ny = 125  # Here y is the vertical axis (number of rows) and not the number of columns

    # The x-axis is varying the fastest
    x = np.arange(0, (nx / 10) + 0.1, 0.1)
    y = np.arange(0, (ny / 10) + 0.1, 0.1)
    sourcex = 0.01
    sourcez = np.arange(0.5, ny / 10, 0.5)
    receiverx = nx / 10 - 0.01
    receiverz = np.arange(0.5, ny / 10, 0.5)
    nsource = len(sourcez)
    nreceiver = len(receiverz)
    ndata = nsource * nreceiver
    data = np.zeros((ndata, 4))
    # Calculate acquisition geometry (multiple-offset gather)
    for jj in range(0, nsource):
        for ii in range(0, nreceiver):
            data[(jj) * nreceiver + ii, :] = np.array(
                [sourcex, sourcez[jj], receiverx, receiverz[ii]])
    # Calculate forward modeling kernel (from Matlab code by Dr. James Irving, UNIL)
    G = tomokernel_straight_2D(
        data, x, y)  # Distance of ray-segment in each cell for each ray
    G = np.array(G.todense())
    del data

    netG = Generator(cuda=cuda, gpath=gpath)
    for param in netG.parameters():
        param.requires_grad = False
    netG.eval()
    if cuda:
        netG.cuda()

    z_hist = np.zeros((maxit, zx * zy)) + np.nan
    labda_hist = np.zeros((maxit)) + np.nan
    rmse_hist = np.zeros((maxit)) + np.nan
    e_hist = np.zeros((maxit, ndata)) + np.nan
    improv_hist = np.zeros((maxit)) + np.nan
    alfa_hist = np.zeros((maxit)) + np.nan
    improv_hist[0] = 1
    best_rmse = 1000
    alfa = np.copy(alfa_min)

    z0 = np.random.randn(zx * zy)
    z = np.copy(z0)
    iter_hist = np.nan

    istart = 0
    iend = maxit

    for i in range(istart, iend):

        z_old = z
        e, J, m_current = comp_res_J(z,
                                     d,
                                     G,
                                     zx,
                                     zy,
                                     nz,
                                     netG,
                                     Prior,
                                     1 / alfa,
                                     mv=None,
                                     CalcJ=FDCalcJ,
                                     cuda=cuda,
                                     Regularization=Regularization,
                                     threshold=threshold,
                                     filtering=filtering)

        rmse = np.sqrt(np.sum(e**2) / len(e))

        # Different ways of updating labda if tried
        if i > 0 and labdaUpdate == 'alternate':
            if np.mod(i, 2) == 0:
                labda = 100
            else:
                labda = 1

        if i > 0 and labdaUpdate == 'constant_SteepDesc':
            labda = np.minimum(labda * 1.1, labda_max)

        if i > 0 and labdaUpdate == 'constant_GN':
            labda = np.maximum(labda * 0.9, labda_min)

        if i > 9 and labdaUpdate == 'dynamic':
            if rmse < rmse_hist[i -
                                1]:  # Decrease labda to get a more GN update
                labda = labda = np.maximum(labda * 0.5, labda_min)
            elif rmse > rmse_hist[
                    i -
                    1]:  # Increase labda to get a more steepest descent update
                labda = np.minimum(labda * 2, labda_max)

        print('Current RMSE is ', rmse)
        if rmse < best_rmse:
            best_rmse = rmse

        # Store z, rmse and labda
        z_hist[i, :] = z.flatten()
        rmse_hist[i] = rmse
        alfa_hist[i] = alfa
        labda_hist[i] = labda
        e_hist[i] = e
        if i > 0 and (rmse > best_rmse):
            improv_hist[i] = 0
        else:
            improv_hist[i] = 1

        # Update z
        dhat = e + J @ z
        A = J.T @ invCe @ J + labda * D @ D.T
        z_new = np.linalg.inv(A) @ J.T @ invCe @ dhat

        # Update alfa if regularization by vanishing smearing or gradual contrasting of the models is tried
        if VaryAlfa == True:
            if np.mod(i, 1) == 0:
                alfa = np.minimum(np.maximum(alfa_min, alfa) * alfa_f, np.inf)
            print(alfa)
            alfa_hist[i] = alfa

        if i >= it_stop and best_rmse > rmse_stop:
            iter_hist = i
            print('Stop non-productive run')
            break
        # Try to reduce the jump if the fit is not improving after some given iterations
        if i >= 20 and AdaptJump == True and np.sum(improv_hist[i - 5:i]) == 0:
            beta = 0.5
            print('reduce jump')
        else:
            beta = 1

        z = z_old + beta * (z_new - z_old)

        print('iteration ', str(i), ' done - best RMSE = ', str(best_rmse))

    return best_rmse, rmse, z_hist, rmse_hist, labda_hist, e_hist, improv_hist, z0, iter_hist
def run_gan_qn(lr, maxiter, gpath, init_z_file, nc, nz, zx, zy, cuda, adam,
               model_index, noise_index, clip):

    # Load initial z (z) if provided
    if init_z_file is None:
        z = torch.rand([1, nz, zx, zy]).to(device) * 2 - 1
    else:
        z = torch.Tensor(init_z_file.reshape(1, nz, zx, zy)).to(device)

    z.requires_grad = True

    # Load true model and measurement data
    model_path = './true_data_model_' + str(model_index) + '_noise_' + str(
        noise_index)
    with open(model_path + '.pkl', 'rb') as fin:
        tmp = pickle.load(fin)
        #z_true=tmp['z_true']
        model_true = tmp['m_true']
        #d_true=tmp['d_true']
        d = tmp['d']

    # forward setup
    from tomokernel_straight import tomokernel_straight_2D

    nx = 60  # Here x is the horizontal axis (number of columns) and not the number of rows
    ny = 125  # Here y is the vertical axis (number of rows) and not the number of columns

    # The x-axis is varying the fastest
    x = np.arange(0, (nx / 10) + 0.1, 0.1)
    y = np.arange(0, (ny / 10) + 0.1, 0.1)
    sourcex = 0.01
    sourcez = np.arange(0.5, ny / 10, 0.5)
    receiverx = nx / 10 - 0.01
    receiverz = np.arange(0.5, ny / 10, 0.5)
    nsource = len(sourcez)
    nreceiver = len(receiverz)
    ndata = nsource * nreceiver
    data = np.zeros((ndata, 4))
    # Calculate acquisition geometry (multiple-offset gather)
    for jj in range(0, nsource):
        for ii in range(0, nreceiver):
            data[(jj) * nreceiver + ii, :] = np.array(
                [sourcex, sourcez[jj], receiverx, receiverz[ii]])
    # Calculate forward modeling kernel (from Matlab code by Dr. James Irving, UNIL)
    A = tomokernel_straight_2D(
        data, x, y)  # Distance of ray-segment in each cell for each ray
    A = np.array(A.todense())
    del data

    netG = Generator(cuda=True, gpath=gpath).to(device)
    for param in netG.parameters():
        param.requires_grad = False
    netG.eval()

    if adam:
        optimizer = optim.Adam([z], lr=lr)
    else:
        optimizer = optim.LBFGS([z], lr=lr)
    data_cost = []
    model_cost = []
    zs = []
    models = []

    filtering = False
    threshold = True

    def closure():
        # Produce model from z

        # clipping
        if clip == 'standard':
            z.data[z.data > 1] = 1
            z.data[z.data < -1] = -1
        if clip == 'stochastic':
            z.data[z.data > 1] = random.uniform(-1, 1)
            z.data[z.data < -1] = random.uniform(-1, 1)

        x0 = netG(z)

        # --- Here we quit pytorch ---
        x = x0.data.cpu().numpy(
        )  # copy x into cpu and numpy for further calculations

        zs.append(z.data.cpu().numpy().copy())

        # Compute cost and gradient on model
        s_model = x[0, 0, 2:127, 3:63]
        s_model = (s_model + 1) * 0.5  # Convert from [-1,1] to [0,1]

        if filtering:
            s_model = medfilt(s_model, kernel_size=(3, 3))

        s_model[s_model < 0.5] = 0
        s_model[s_model >= 0.5] = 1

        s_model[s_model == 0] = 0.08  # m/ns
        s_model[s_model == 1] = 0.06  # m/ns
        s_model = 1 / s_model

        sim = A @ s_model.flatten(order='F')
        e = d - sim

        cost = np.sum(np.power(e, 2))

        grad = -2 * A.T @ e.T
        # change from Fortran ordering used by forward solver to C ordering used by numpy
        grad = grad.reshape((125, 60), order='F').reshape((7500))

        # embed grad within array of the size used by the GAN
        grad_fs = np.zeros((129, 65))
        grad_fs[2:127, 3:63] = grad.reshape((125, 60))

        data_cost.append(cost)
        model_cost.append(np.linalg.norm(model_true - x[0, 0, 2:127, 3:63]))

        # Update z (z) using gradient information
        #--- Here we go back to pytorch ---
        optimizer.zero_grad()
        x0.backward(torch.Tensor(grad_fs.reshape(x0.shape)).to(device))
        return cost

    for it in range(maxiter):

        optimizer.step(closure)

        print(it, data_cost[-1], model_cost[-1])

        # Stop non-productive runs
        if it >= 100 and data_cost[-1] > 1e3:
            break

    x = netG(z)

    return z.data.cpu().numpy(), x.data.cpu().numpy(
    ), data_cost, model_cost, zs, models
def run_gan_qn(lr, maxiter, gpath, init_z_file,nc,nz,zx,zy,cuda,adam,model_index,noise_index,clip):

    def ssr_loss(true,sim):
        return torch.sum((true-sim)**2)
    
    # Load initial z (z) if provided
    if init_z_file is None:
        z = torch.rand([1, nz, zx, zy]).to(device)*2-1
    else:
        z = torch.Tensor(init_z_file.reshape(1, nz, zx, zy)).to(device)

    z.requires_grad = True

    # Load true model and measurement data
    model_path = './true_model_'+str(model_index)+'_noise_'+str(noise_index)
    with open(model_path+'.pkl', 'rb') as fin:
        tmp=pickle.load(fin)
        z_true=tmp['z_true']
        m_true=torch.Tensor(tmp['m_true_cont'] ).to(device)#125 x 60 in [0,1]
        d=torch.Tensor(tmp['d_cont'] ).to(device)

    # forward setup
    from tomokernel_straight import tomokernel_straight_2D
    
    nx=60 # Here x is the horizontal axis (number of columns) and not the number of rows
    ny = 125 # Here y is the vertical axis (number of rows) and not the number of columns

    # The x-axis is varying the fastest 
    x = np.arange(0,(nx/10)+0.1,0.1)                      
    y = np.arange(0,(ny/10)+0.1,0.1) 
    sourcex = 0.01
    sourcez = np.arange(0.5,ny/10,0.5)                         
    receiverx = nx/10-0.01
    receiverz = np.arange(0.5,ny/10,0.5)   
    nsource = len(sourcez); nreceiver = len(receiverz)
    ndata=nsource*nreceiver
    data=np.zeros((ndata,4))
    # Calculate acquisition geometry (multiple-offset gather)
    for jj in range(0,nsource):
        for ii in range(0,nreceiver):
            data[ ( jj ) * nreceiver + ii , :] = np.array([sourcex, sourcez[jj], receiverx, receiverz[ii]])
    # Calculate forward modeling kernel (from Matlab code by Dr. James Irving, UNIL)
    A = tomokernel_straight_2D(data,x,y) # Distance of ray-segment in each cell for each ray
    A=A.todense()
    A=torch.Tensor(A).to(device)
    del data
    
    netG = Generator(cuda=True, gpath=gpath).to(device)
    for param in netG.parameters():
        param.requires_grad = False
    netG.eval()

    if adam:
        optimizer = optim.Adam([z], lr=lr)
    else:
        optimizer = optim.LBFGS([z], lr=lr)
    data_cost = []
    model_cost = []
    zs = []
    models = []
    
    # train
    for i in range(maxiter):
        # clipping
        if clip == 'standard':
            z.data[z.data> 1] = 1
            z.data[z.data < -1] = -1
        if clip == 'stochastic':
            z.data[z.data > 1] = random.uniform(-1, 1)
            z.data[z.data < -1] = random.uniform(-1, 1)
        
        x0 = netG(z)[0,0,2:127,3:63]

        x0 = (x0 + 1) * 0.5  # Convert from [-1,1] to [0,1]
        s = 1 - x0
        s= 0.06 + s*0.02
        s=1/s #ns/m
        # change from C ordering to Fortran ordering and reshape
        s=s.permute(1,0).flatten().view(7500,1)
        
        sim = torch.mm(A,s).flatten()
        
        ssr = ssr_loss(d,sim)
        
        ssr_model = ssr_loss(x0,m_true)
#        if i % 10 == 0:
#            print("[Iter {}] ssr_g_z: {}, ssr_g_z: {}, ssr_model: {}"
#                  .format(i, ssr.data[0], ssr, ssr_model.data[0]))

        # backprop
        optimizer.zero_grad()
        ssr.backward()
        optimizer.step()

        data_cost.append(ssr.detach().cpu().numpy())
        model_cost.append(ssr_model.detach().cpu().numpy())
        zs.append(z.detach().cpu().numpy())
#        models.append(x0.detach().cpu.numpy())
        
        print(i, data_cost[-1], model_cost[-1])

    return  z, x0, data_cost, model_cost, zs, models