直接偏好优化技术DPO基础理论及推导

论文标题:Direct Preference Optimization: Your Language Model is Secretly a Reward Model
论文链接:https://arxiv.org/abs/2305.18290
论文来源:NeurIPS 2023

一、概述

为了能够将语言模型的行为与人类偏好对齐,现有的方法使用精心设计的人类偏好数据集集,将期望的行为灌输到语言模型中,这些偏好数据集代表了人类认为安全和有益的行为类型。目前的大模型偏好对齐主要依赖于基于人类反馈的强化学习技术(Reinforcement Learning from Human Feedback, RLHF),RLHF方法利用奖励模型(Reward Model)拟合人类偏好数据集,然后使用强化学习技术优化语言模型策略(policy),以使其能够产生高奖励的响应,且不会偏离原始模型太远。虽然RLHF训练的模型具有令人印象深刻的对话和编码能力,但RLHF pipeline比监督学习要复杂得多,涉及在训练循环中训练多个语言模型并从语言模型策略中采样,这会造成巨大的计算成本。

本文研究验证了现有方法使用的基于强化学习的目标可以用一个简单的二元交叉熵目标来直接优化,无需奖励模型与强化学习,由此简化了偏好学习的pipeline。本文提出直接偏好优化(Direct Preference Optimization, DPO)技术,能够隐式地优化与现有RLHF算法相同的目标(即在一个KL散度约束下最大化奖励),且很容易实现和能够直接训练。DPO更新过程会增大偏好响应相较于不偏好响应的log概率,同时其包含一个动态的、每个样本上的重要性权重,以避免模型退化(这种退化在使用朴素的概率比值目标时会发生)。

与现有的方法类似,DPO依赖于一种理论偏好模型(比如Bradley-Terry模型),这一类模型度量一个给定的奖励函数(Reward Function)对齐经验偏好数据的好坏程度。不同的是,DPO并没有采用训练奖励模型以及强化学习的方式,而是利用一种奖励模型的重参数化技巧,使得能够闭式地(in close form)获取最优的策略模型。给定模型响应的人类偏好数据集,DPO可以使用简单的二元交叉熵目标来优化策略,得到适合偏好数据的隐式奖励函数的最优策略。

二、前提

RLHF pipeline通常包含三个阶段:1)监督微调(Supervised Fine-Tuning, SFT);2)偏好采样和奖励学习;3)强化学习优化。

  1. SFT阶段

RLHF通常从在一个预训练语言模型上利用下游任务(如对话、总结等)的高质量演示数据监督微调开始,来获得一个模型\pi ^{\text{SFT}}。

  1. 奖励建模阶段

在第二阶段,利用promptx来使得SFT模型产生成对的响应(y_{1},y_{2})\sim \pi ^{\text{SFT}}(y|x)。这些响应接着将由人类标注更加偏好哪一个,标注为y_w\succ y_l|x,这里的y_wy_l分别表示(y_{1},y_{2})偏好的和不偏好的补全。现在假设这些偏好符合某个隐式奖励模型r^*(x,y),也就是我们无法直接访问的奖励函数的真实分布。

通常有一些可用于建模偏好的模型,例如Bradley-Terry (BT)模型(如果我们有几个排名的答案的话,可以采用更一般的Plackett-Luce排名模型)。BT模型的基本思想是,通过对各个对象进行配对比较,可以估计出每个对象的“实力”或“能力”,从而计算出在任意一对对象之间进行比较时,某个对象获胜的概率。具体来说,假设有n个对象(例如运动员、产品等),我们用\theta_i表示对象i的实力参数。对于两个对象ij,对象i在比较中获胜的概率P(i\succ j)可以表示为:

P(i\succ j) = \frac{\theta_i}{\theta_i + \theta_j} \tag{1}

其中,\theta_i\theta_j都是正的实力参数。BT模型广泛应用于竞技体育排名、音乐和艺术竞赛、市场研究中的产品比较等领域。通过配对比较,Bradley-Terry模型能够提供一个相对简单但有效的框架来比较多个对象的相对实力或偏好。

在偏好对齐的场景下,BT模型可将真实的人类偏好分布p^*建模为:

p^*(y_1\succ y_2|x)=\frac{\text{exp}(r^*(x,y_1))}{\text{exp}(r^*(x,y_1))+\text{exp}(r^*(x,y_2))} \tag{2}

真实的奖励函数r^*与真实的偏好分布p^*都是不可访问的,不过我们可以通过人类标注的方式获得从p^*中采样的人类偏好数据集\mathcal{D}=\left \{x^{(i)},y_{w}^{(i)},y_{l}^{(i)}\right \}_{i=1}^{N},然后利用这个数据集即可参数化一个奖励模型r_\phi (x,y),并根据极大似然估计来估计其参数。将这个问题作为一个二分类问题的话,我们便有了RLHF中建模奖励函数的负对数似然损失:

\mathcal{L}_{R}(r_\phi ,\mathcal{D})=-\mathbb{E}_{(x,y_w,y_l)\sim \mathcal{D}}\left [\text{log}\, \sigma (r_\phi (x,y_w)-r_\phi (x,y_l))\right ] \tag{3}

其中\sigma为Logistic函数。在语言模型的场景下,奖励函数r_\phi (x,y)通常从SFT模型\pi ^{\text{SFT}}(y|x)初始化而来,在其最后一个transformer层的顶部添加一个线性层,使其输出一个标量预测值作为奖励值。为了确保这个奖励函数具有低方差,现有方法通常会标准化奖励值,即\mathbb{E}_{(x,y)\sim \mathcal{D}}[r_\phi (x,y)]=0。

  1. 强化学习微调阶段

在强化学习阶段,我们使用前一阶段学习到的奖励函数来为语言模型提供反馈,通常强化学习阶段相当于以下优化问题:

\max_{\pi _{\theta }}\mathbb{E}_{x\sim \mathcal{D},y\sim \pi _{\theta }(y|x)}\left [r_\phi (x,y)\right ]-\beta \mathbb{D}_{KL}\left [\pi _{\theta }(y|x)\parallel \pi _{\text{ref}}(y|x)\right ] \tag{4}

这里的\beta是一个超参数,用于控制偏离基础参考策略(reference policy)\pi _{\text{ref}}的程度,\pi _{\text{ref}}也就是初始的SFT模型\pi ^{\text{SFT}}(y|x),在优化过程中其参数是固定的。\pi _{\theta }为实际优化的策略模型,通常策略模型也由\pi ^{\text{SFT}}(y|x)初始化而来。上式的KL散度约束是很重要的,因为奖励模型r_\phi (x,y)是在SFT模型\pi ^{\text{SFT}}(y|x)的输出分布上训练得到的,因此只有在这个分布上奖励模型的预测值才是准确的,这个KL散度约束防止了策略模型的输出分布偏离\pi ^{\text{SFT}}(y|x)的输出分布,同时也保持了生成内容的多样性并且防止模式坍塌到单一的高奖励答案。

由于语言生成的离散性,上面的目标是不可微的,因此通常使用强化学习来优化这个目标。标准的方法将奖励函数构造成r(x,y)=r_\phi (x,y)-\beta (\text{log}\, \pi _{\theta }(y|x)-\text{log}\, \pi _{\text{ref}}(y|x)),然后使用PPO来最大化这个奖励函数。RLHF的详细流程可参考生成式大模型的RLHF技术(一):基础。

三、方法

本文的目标是推导出一种直接使用偏好的策略优化方法,不像之前的RLHF方法需要学习一个奖励模型然后利用强化学习来优化策略模型,本文的方法利用一种特殊的奖励模型参数化,使得能够闭式地获取最优的策略模型,而不需要一个强化学习的训练过程。DPO利用从奖励函数到最优策略的解析映射推导,使得我们能够将奖励函数上的损失转换为策略模型上的损失。这种变量改变方法避免了拟合一个显式的、独立的奖励模型,同时仍然在现有的人类偏好模型下(即BT模型)进行优化。本质上,策略模型同时代表了语言模型和(隐式的)奖励模型。

  1. DPO目标的推导

对于前面的KL散度约束的奖励最大化目标公式(4),其在一般的奖励函数r(x,y)下的最优解\pi _{r}(y|x)为:

\pi _{r}(y|x)=\frac{1}{Z(x)}\pi _{\text{ref}}(y|x)\text{exp}\left (\frac{1}{\beta }r(x,y)\right ),\; \text{for all }x\in \mathcal{D} \tag{5}

这里的Z(x)=\sum _{y}\pi _{\text{ref}}(y|x)\text{exp}\left (\frac{1}{\beta }r(x,y)\right ),详细推导请参看本文最后一个章节的第1小节。对于Z(x)而言,其中的r(x,y)我们可以通过ground-truth奖励函数r^*的极大似然估计r_{\phi}来得到,但配分函数Z(x)的估计仍然是unfeasible的。这是因为xy作为语言模型的输入输出文本,其状态空间非常地广阔。因此这个最优解的表示在实践中是很难计算的。不过我们可以重新排列公式(5)来用最优策略\pi _{r}、参考策略\pi _{\text{ref}}以及未知的配分函数Z(x)来重参数化奖励函数r(x,y)

r(x,y)=\beta \, \text{log}\frac{\pi _{r}(y|x)}{\pi _{\text{ref}}(y|x)}+\beta \, \text{log}Z(x) \tag{6}

公式(6)中的重参数化设计可以应用到ground-truth奖励r^{*}和对应的最优策略模型\pi ^{*}上。幸运的是,BT模型只依赖于两个补全的奖励的差值p^*(y_1\succ y_2|x)=\sigma (r^*(x,y_1)-r^*(x,y_2)),详细推导请参看本文最后一个章节的第2小节。用r^{*}(x,y)\pi ^{*}(y|x)替换公式(6)中的r(x,y)\pi _{r}(y|x),然后将r^{*}(x,y)代入BT模型,即可使用最优策略模型\pi ^{*}和参考模型\pi _{ref}来表示人类偏好概率,也就是说BT模型下的最优的RLHF策略模型\pi ^{*}满足以下偏好模型:

p^*(y_1\succ y_2|x)=\frac{1}{1+exp\left (\beta \, \text{log}\frac{\pi ^{*}(y_{2}|x)}{\pi _{\text{ref}}(y_{2}|x)}-\beta \, \text{log}\frac{\pi ^{*}(y_{1}|x)}{\pi _{\text{ref}}(y_{1}|x)}\right )} \tag{7}

现在我们有了以最优策略模型表示(而非以奖励模型表示)的人类偏好概率,因此我们就可以使用一个面向一个参数化策略模型\pi _{\theta }的极大似然目标。类似于公式(3)中的奖励建模过程,我们的策略目标函数变为了:

\mathcal{L}_{\text{DPO}}(\pi _{\theta };\pi _{\text{ref}})=-\mathbb{E}_{(x,y_{w},y_{l})\sim \mathcal{D}}\left [\text{log}\, \sigma \left (\beta \, \text{log}\frac{\pi _{\theta }(y_{w}|x)}{\pi _{\text{ref}}(y_{w}|x)}-\beta \, \text{log}\frac{\pi _{\theta }(y_{l}|x)}{\pi _{\text{ref}}(y_{l}|x)}\right )\right ] \tag{8}

于是,我们现在利用一个替代参数化来拟合隐式奖励,其最佳策略为优化后的\pi _{\theta }。此外,由于该过程等价于拟合一个重新参数化的BT模型,因此该过程具有一定的理论性质,比如在适当的偏好数据分布假设下的一致性。

  1. DPO更新做了什么?

为了更好地理解DPO,我们可以分析一下DPO损失函数\mathcal{L}_{\text{DPO}}的梯度,其在参数\theta上的梯度可以写作:

\nabla _{\theta }\mathcal{L}_{\text{DPO}}(\pi _{\theta };\pi _{\text{ref}})=-\beta \mathbb{E}_{(x,y_{w},y_{l})\sim \mathcal{D}}\left [\underbrace{\sigma (\hat{r}_{\theta }(x,y_{l})-\hat{r}_{\theta }(x,y_{w}))}_{\text{higher weight when reward estimate is wrong}}\left [\underbrace{\nabla _{\theta }\, \text{log}\, \pi _{\theta }(y_{w}|x)}_{\text{increase likelihood of }y_{w}}-\underbrace{\nabla _{\theta }\, \text{log}\, \pi _{\theta }(y_{l}|x)}_{\text{decrease likelihood of }y_{l}}\right ] \right ] \tag{9}

这里的\hat{r}_{\theta }(x,y)=\beta \, \text{log}\frac{\pi _{\theta }(y|x)}{\pi _{\text{ref}}(y|x)}是由语言模型\pi _{\theta }和参考模型\pi _{\text{ref}}隐式定义的奖励。直观来看,损失函数\mathcal{L}_{\text{DPO}}的梯度增加了偏好补全y_{w}的似然,并降低了不偏好补全y_{l}的似然。需要注意的是,这些样本的权重取决于隐式奖励模型\hat{r}_{\theta }对不偏好的补全进行评分的高低程度,缩放因子为\beta,即隐式奖励模型对这些补全排序的错误程度,同时考虑到KL散度约束的强度。本文的实验表明了这种加权的重要性,因为这种方法的朴素版本如果没有加权系数,可能会导致语言模型退化。

  1. DPO pipeline

DPO的整体pipeline为:
①对每个promptx采样补全y_{1},y_{2}\sim \pi _{\text{ref}}(\cdot |x),并由人类标注以获得离线偏好数据集\mathcal{D}=\left \{x^{(i)},y_{w}^{(i)},y_{l}^{(i)}\right \}_{i=1}^{N};
②对于给定的\pi _{\text{ref}}、\mathcal{D}\beta,优化\pi _{\theta }来最小化\mathcal{L}_{\text{DPO}}。

在DPO方法中,由于偏好数据集是从\pi ^{\text{SFT}}采样而来,因此我们设置\pi _{\text{ref}}=\pi ^{\text{SFT}}。在实践中,人们可能会希望直接使用公开可用的偏好数据集,而不是自己生成样本并收集人类的偏好。在这种情况下\pi ^{\text{SFT}}是不可访问的,因此我们通过最大化偏好补全(x,y_{w})的似然来初始化\pi _{\text{ref}},即\pi _{\text{ref}}=\text{arg}\,\max_{\pi }\mathbb{E}_{x,y_{w}\sim \mathcal{D}}[\text{log}\, \pi (y_{w}|x)]。这一设置有助于缓解DPO在不可用的真实参考分布和\pi _{\text{ref}}之间的分布偏移。

推导

本节补充一些前文省略的公式推导过程。

  1. 推导KL散度约束的奖励最大化目标的最优解

首先对于前面的公式(4),其在任意奖励函数r(x,y)和一般的非参数化策略类\pi (y|x)下的一般形式为:

\max_{\pi }\mathbb{E}_{x\sim \mathcal{D},y\sim \pi (y|x)}\left [r(x,y)\right ]-\beta \mathbb{D}_{KL}\left [\pi (y|x)\parallel \pi _{\text{ref}}(y|x)\right ] \tag{10}

在该式基础上,有以下推导过程:

\begin{align} &\max_{\pi }\mathbb{E}_{x\sim \mathcal{D},y\sim \pi (y|x)}\left [r(x,y)\right ]-\beta \mathbb{D}_{KL}\left [\pi (y|x)\parallel \pi _{\text{ref}}(y|x)\right ]\\ &=\max_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\mathbb{E}_{y\sim \pi (y|x)}\left [r(x,y)\right ]-\mathbb{E}_{x\sim \mathcal{D}}\mathbb{E}_{y\sim \pi (y|x)}\left [\beta \, \text{log}\frac{\pi (y|x)}{\pi _{\text{ref}}(y|x)}\right ]\\ &=\max_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\mathbb{E}_{y\sim \pi (y|x)}\left [r(x,y)-\beta \, \text{log}\frac{\pi (y|x)}{\pi _{\text{ref}}(y|x)}\right ]\\ &=\min_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\mathbb{E}_{y\sim \pi (y|x)}\left [\beta \, \text{log}\frac{\pi (y|x)}{\pi _{\text{ref}}(y|x)}-r(x,y)\right ]\\ &=\min_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\mathbb{E}_{y\sim \pi (y|x)}\left [\text{log}\frac{\pi (y|x)}{\pi _{\text{ref}}(y|x)}-\frac{1}{\beta }r(x,y)\right ]\\ &=\min_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\mathbb{E}_{y\sim \pi (y|x)}\left [\text{log}\frac{\pi (y|x)}{\pi _{\text{ref}}(y|x)\text{exp}\left (\frac{1}{\beta }r(x,y)\right )}\right ]\\ &=\min_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\mathbb{E}_{y\sim \pi (y|x)}\left [\text{log}\frac{\pi (y|x)}{\frac{1}{Z(x)}\pi _{\text{ref}}(y|x)\text{exp}\left (\frac{1}{\beta }r(x,y)\right )}-\text{log}\, Z(x)\right ] \end{align}

这里的Z(x)为配分函数:

Z(x)=\sum _{y}\pi _{\text{ref}}(y|x)\text{exp}\left (\frac{1}{\beta }r(x,y)\right ) \tag{11}

注意这里的Z(x)只与x和参考策略\pi _{\text{ref}}有关,不依赖于策略\pi。现在我们可以定义:

\pi ^{*}(y|x)=\frac{1}{Z(x)}\pi _{\text{ref}}(y|x)\text{exp}\left (\frac{1}{\beta }r(x,y)\right ) \tag{12}

这里的\pi ^{*}(y|x)满足\pi ^{*}(y|x)\ge 0\sum _{y}\pi ^{*}(y|x)=1,因此实际上我们是定义了一个有效的概率分布\pi ^{*}(y|x)。由于Z(x)不是y的函数,我们可以重新组织一下公式(11),继续以下推导过程:

\begin{align} &\min_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\mathbb{E}_{y\sim \pi (y|x)}\left [\text{log}\frac{\pi (y|x)}{\frac{1}{Z(x)}\pi _{\text{ref}}(y|x)\text{exp}\left (\frac{1}{\beta }r(x,y)\right )}-\text{log}\, Z(x)\right ]\\ &=\min_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\mathbb{E}_{y\sim \pi (y|x)}\left [\text{log}\frac{\pi (y|x)}{\pi ^{*}(y|x)}-\text{log}\, Z(x)\right ]\\ &=\min_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\left [\mathbb{E}_{y\sim \pi (y|x)}\left [\text{log}\frac{\pi (y|x)}{\pi ^{*}(y|x)}\right ]-\text{log}\, Z(x)\right ]\\ &=\min_{\pi }\mathbb{E}_{x\sim \mathcal{D}}\left [\mathbb{D}_{KL}(\pi (y|x)\parallel \pi ^{*}(y|x))-\text{log}\, Z(x)\right ] \end{align}

现在,由于Z(x)并不依赖于\pi,因此上述目标的最小值将会在第一个KL散度项最小时达成。由吉布斯不等式可知,当且仅当两个概率分布完全相同时KL散度达到最小值0。因此我们所求的\pi (y|x)的最优解即为\pi ^{*}(y|x)

\pi (y|x)=\pi ^{*}(y|x)=\frac{1}{Z(x)}\pi _{\text{ref}}(y|x)\text{ep}\left (\frac{1}{\beta }r(x,y)\right ),\; \text{for all }x\in \mathcal{D} \tag{13}

  1. BT模型下DPO目标推导

对于公式(2)中展示的BT模型对人类偏好的建模,可以做以下转换:

\begin{align} &p^*(y_1\succ y_2|x)=\frac{\text{exp}(r^*(x,y_1))}{\text{exp}(r^*(x,y_1))+\text{exp}(r^*(x,y_2))}\\ &=\frac{1}{1+\text{exp}(r^*(x,y_2)-r^*(x,y_1))}\\ &=\sigma (r^*(x,y_1)-r^*(x,y_2)) \tag{14} \end{align}

这里的\sigma为sigmoid函数。根据公式(6)可知我们可以将不可访问的ground truth奖励函数r^{*}用最优的策略\pi ^{*}来表示:

r^{*}(x,y)=\beta \, \text{log}\frac{\pi ^{*}(y|x)}{\pi _{\text{ref}}(y|x)}+\beta \, \text{log}Z(x) \tag{15}

将公式(15)代入公式(14)即可得:

p^*(y_1\succ y_2|x)=\sigma \left (\beta \, \text{log}\frac{\pi ^{*}(y_{1}|x)}{\pi _{\text{ref}}(y_{1}|x)}-\beta \, \text{log}\frac{\pi ^{*}(y_{2}|x)}{\pi _{\text{ref}}(y_{2}|x)}\right ) \tag{16}

这个概率即是公式(8)中所采用的单实例损失。

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,992评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,212评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,535评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,197评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,310评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,383评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,409评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,191评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,621评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,910评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,084评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,763评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,403评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,083评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,318评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,946评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,967评论 2 351

推荐阅读更多精彩内容