张量网络编程学习笔记(3-2):TN_Tutorial自动微分门量子线路的模块化编程:AD_Circuits/ADgate.py + /ADQC_QSP1.py + /ADQC_QSP2.py

文件参照 TN_Tutorial.AD_Circuits 的 ADgate.py,ADQC_QSP1.py,ADQC_QSP2.py

本文仅从本人复习需要出发:作为对首都师范大学冉仕举老师课程内容的整理、归纳以及补充

课程详情:张量网络PyThon编程:3.4 量子线路模块化编程(a) ADGate类_哔哩哔哩_bilibili

冉仕举老师本人空间:StringCNU的个人空间_哔哩哔哩_bilibili

github文件_TN_Tutorial:Add files via upload · ranshiju/Python-for-Tensor-Network-Tutorial@c76f4a2 (github.com)

* 模块化编程(1)- 系统地调用门(ADGate)

(1)ADQC怎样建立门的:(看源码),重要属性:self.name, self.paras, self.tensor 变分or固定门

# ============================ 以下是非参数门,============================
        if self.name in ['x', 'y', 'z']:
            self.tensor = mf.pauli_operators(self.name)
            self.tensor = self.tensor.to(device=self.device, dtype=self.dtype)
            self.variational = False
        elif self.name in ['hadamard', 'h']:
            self.tensor = mf.hadamard()
            self.tensor = self.tensor.to(device=self.device, dtype=self.dtype)
            self.variational = False
        elif self.name in ['gate_no_variation']:
            self.paras = paras
            self.tensor = paras
            self.variational = False
# ============================ 以下是参数门,==============================
        elif self.name == 'rotate':
            if paras is None:
                self.paras = tc.randn((4, ))
            self.paras = self.paras.to(device=self.device)
        elif self.name in ['rotate_x', 'rotate_y', 'rotate_z', 'phase_shift']:
            if paras is None:
                self.paras = tc.randn(1)
            self.paras = self.paras.to(device=self.device)
        elif self.name == 'evolve_variational_mag':  # 单体磁场演化, shape=(2, )
            assert 'tau' in self.settings
            assert 'h_directions' in self.settings
            if paras is None:
                self.paras = tc.randn((len(self.settings['h_directions']), ))
            self.paras = self.paras.to(device=self.device, dtype=tc.float64)
        elif self.name == 'latent':
            if paras is None:
                if self.pos is None:
                    ndim = 2
                else:
                    ndim = len(self.pos)
                if qudit_dims is None:
                    qudit_dims = [2] * ndim
                dim_t = math.prod(qudit_dims)
                if 'initial_way_latent' in self.settings:
                    if self.settings['initial_way_latent'] == 'identity':
                        self.paras = tc.eye(dim_t, dim_t) + 1e-5 * tc.randn((dim_t, dim_t))
                else:
                    self.paras = tc.randn((dim_t, dim_t))
            self.paras = self.paras.to(device=self.device, dtype=self.dtype)
        elif self.name == 'arbitrary':  # 传入一个paras矩阵作为门
            assert type(paras) is tc.Tensor
            self.paras = paras.to(device=self.device, dtype=self.dtype)
            self.tensor = self.paras
        if self.variational:
            self.paras = nn.Parameter(self.paras, requires_grad=True)
        self.renew_gate()

更新门参数注意要赋值到 gate.paras.data =tc.tensor (...) ,paras有一个自动微分属性:除非手动将待传系数张量给赋予自动微分属性:tc.nn.Parameters(tc.tensor(...) ) , 加入require_grad = True

我们在命令行里测试一下:非参数门:hadamard

  

参数门 : rotate_x (0.5) ~ (1.0)

(注意,需要renew转角,否则就是临时储存在gate.paras.data里面)

 

 矩阵参数门:latent,arbitary(U4门)

     latent_gate 内部的自动更新.renew_gate( )  是怎么实现的 以及 初始化的特色:

        elif self.name == 'latent':
            # 无参数初始化
            if paras is None:
                # 默认二体门
                if self.pos is None:
                    ndim = 2
                else:
                    ndim = len(self.pos)
                # 默认2-qbit
                if qudit_dims is None:
                    qudit_dims = [2] * ndim
                dim_t = math.prod(qudit_dims)
                if 'initial_way_latent' in self.settings:
                # 深层隐门网络,初始化建议是I + [ \epsilon ]
                # 这样可以缓解梯度消失
                    if self.settings['initial_way_latent'] == 'identity':
                        self.paras = tc.eye(dim_t, dim_t) + 1e-5 * tc.randn((dim_t, dim_t))
                else:
                    self.paras = tc.randn((dim_t, dim_t))
             
             # 含参数初始化
             self.paras = self.paras.to(device=self.device, dtype=self.dtype)

  可本人测试了一下,肉眼单次看tensor好像两者规格上没有什么显著差别()

   U4 门暂且不测试了,,,

* 模块化编程(2)- 把一组门给打包:qc = ADQC.ADQC_basic 

 回到态制备问题,如图例先是经典变分门线路 :

  还是要先初始化量子态:

num_qubits = 3
# 初始化目标态
psi_target = tc.randn((2**num_qubits, ),
                      dtype=tc.complex128, device=device)
psi_target /= psi_target.norm()
#--------------------------------------------------------------#
# 初始化量子态|000>,仅作示例,将在每一轮优化里重新定义一次
psi = state_all_up(n_qubit=num_qubits, d=2).to(
                      device=device, dtype=psi_target.dtype)
psi = qc(psi)​

  逐行逐门添加的 (ADQC_QSP1.py): 

# print('建立ADQC_basic实例')
qc = ADQC.ADQC_basic()
# print('在ADQC_basic实例中添加ADgate实例')
qc.add_ADgates(ADQC.ADGate('rotate', pos=0))
qc.add_ADgates(ADQC.ADGate('x', pos=1, pos_control=0))
qc.add_ADgates(ADQC.ADGate('rotate', pos=0))
qc.add_ADgates(ADQC.ADGate('rotate', pos=1))
qc.add_ADgates(ADQC.ADGate('x', pos=2, pos_control=1))
qc.add_ADgates(ADQC.ADGate('rotate', pos=1))
qc.add_ADgates(ADQC.ADGate('rotate', pos=2))
qc.add_ADgates(ADQC.ADGate('x', pos=0, pos_control=2))
qc.add_ADgates(ADQC.ADGate('rotate', pos=2))

# print('打印各个门及变分参数')
for x in qc.state_dict():
    print(x, qc.state_dict()[x])

  有封装好的 全latent_gate 线路(ADQC_QSP2.py) :

num_qubits = 3

​# print('建立ADQC_basic实例')
qc = ADQC.ADQC_LatentGates(
    # 其实 lattice='brick' or 'stair',
    # 两种选择等价
    lattice = 'brick',
    num_q = num_qubits,
    depth = 2)
# print('每层二体门作用的位置为:')
print(qc.pos)
# 会返回:[[0, 1], [1, 2]]

# print('ADQC的变分参数维数为:')
for x in qc.state_dict():
    print(qc.state_dict()[x].shape)​

搭建基于ADQC_latent的分类器,有封装好的线路(ADQC_iris数据集分类):

实现ADQC_LatentGates对线路的打包:开两个循环 nd 和 ng :

逐深度与逐层对 LatentGates进行添加

向 nn.Sequential 写入 add_module() :ADGate,是用 nn.Module建立的实例

这些参数是量子门的变分参数。self.Layers,作为储存全部量子门的属性,由Sequential建立

 运行属性的原理(single_state),我们留在下一节细讲:

毕竟是变分算法,实现参数更新:向前传播 + optimizer + 反向传播 ~ 写法类似于神经网络:

注释一下:ADQC训练过程 

optimizer = Adam(qc.parameters(), lr=lr)  # 建立优化器
loss_rec = tc.zeros(it_time, )
# 储存 loss_rec,后面打印
print('开始优化')
for t in range(it_time):
    # 建立初态|000>
    psi = state_all_up(n_qubit=num_qubits, d=2).to(
        device=device, dtype=psi_target.dtype)
    psi = qc(psi)
    # 向前传播,同:qc,forward(psi)
    loss = 1 - psi.flatten().dot(psi_target.conj()).norm()
    loss.backward()
    optimizer.step()
    optimizer.zero_grad()
    loss_rec[t] = loss.item()
    if t % 20 == 19:
        print('第%d次迭代,loss = %g' % (t, loss.item()))
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值