LLM大语言模型算法特训,带你转型AI大语言模型算法工程师[完结8周]

81 阅读6分钟

参考资料地址1:pan.baidu.com/s/12IC3iLv8… 提取码: aj1i 参考资料地址2:share.weiyun.com/grO4IKgp 密码:bfvf7y

大语言模型是一种基于神经网络的自然语言处理技术,可以学习和预测自然语言文本的规律和模式。简单来说,大语言模型就是一个能够理解和生成自然语言的AI程序。在大语言模型中,神经网络模型可以通过学习大量的语料数据,来自动地提取自然语言文本中的特征和模式,从而实现自然语言的理解和生成。 具体来说,大语言模型的基本思想是将自然语言文本看作是一种序列数据,例如单词序列或字符序列。神经网络模型可以通过输入这些序列数据,并通过多层神经元的计算和转换,来生成对应的输出序列。在大语言模型中,神经网络模型通常采用循环神经网络(RNN)、长短时记忆网络(LSTM)、门控循环单元(GRU)等结构,来处理序列数据的信息。

大语言模型的发展可以追溯到上世纪80年代,当时科学家们开始尝试使用神经网络来处理自然语言。但由于当时计算机硬件和数据资源的限制,这些神经网络模型往往只能处理非常简单的自然语言任务。 随着计算机硬件和数据资源的不断提升,神经网络模型在自然语言处理领域的应用也得到了快速发展。在2010年左右,科学家们开始尝试使用深度神经网络来进行自然语言处理,例如使用卷积神经网络进行文本分类等任务。 在2013年,Tomas Mikolov等人提出了一种基于循环神经网络(RNN)的语言模型,称为RNNLM。这种模型可以根据前面的单词来预测下一个单词,从而实现对文本的生成和预测。RNNLM不仅可以生成自然语言文本,还可以用于机器翻译、语音识别等任务。 在2014年,Bengio等人提出了一种基于长短时记忆网络(LSTM)的语言模型,称为LSTMLM。这种模型可以解决RNNLM中存在的梯度消失和梯度爆炸等问题,并且可以在更长的上下文中进行预测和生成。 在2018年,OpenAI推出了第一代GPT模型,其参数量达到了1.17亿个。这个模型在各种自然语言处理任务中都取得了非常好的效果,例如文本分类、语言模型等。而在2019年,OpenAI推出了更加强大的第二代GPT模型,其参数量达到了15亿个。这个模型在生成自然语言文本方面表现出了更加出色的性能,例如可以生成更长、更连贯的文本。

大规模语言模型的发展历程虽然只有短短不到五年的时间,但是发展速度相当惊人,截止2023年6 月,国内外有超过百种大模型相继发布。中国人民大学赵鑫教授团队在文献按照时间线给出2019 年至2023 年5 月比较有影响力并且模型参数量超过100 亿的大规模语言模型

大规模语言模型构建流程 根据OpenAI 联合创始人Andrej Karpathy 在微软Build 2023 大会上所公开的信息,OpenAI 所使用的大规模语言模型构建流程如图2.2所示。主要包含四个阶段:预训练、有监督微调、奖励建模、强化学习。这四个阶段都需要不同规模数据集合、不同类型的算法,产出不同类型的模型,所需要的资源也有非常大的差别。

未来大语言模型用在推荐里有如下几个可以发力的场景: 第一个就是冷启动和长尾问题; 第二个是引入外部知识,现在引入外部知识的手段还比较粗糙,就是把大语言模型拿来生成,其实纯用语言模型也没有很多外部知识。相反,语言模型也需要外部的知识,比如它需要集成一些检索能力,需要集成一些工具调用的能力。现在我们只用了基础的语言模型,并没有用它的检索和工具调用的能力。未来能够更加高效地、更加完备地引入更多的外部知识,通过检索或者工具的方式,也是提升推荐体验的一个方向。 第三个改善交互体验,让用户可以主动通过交互时界面自由地描述其需求,从而实现精准推荐。

deepValueEqual()函数实现如下: type visit struct { a1 unsafe.Pointer a2 unsafe.Pointer typ Type }

func deepValueEqual(v1, v2 Value, visited map[visit]bool) bool { if !v1.IsValid() || !v2.IsValid() { return v1.IsValid() == v2.IsValid() } if v1.Type() != v2.Type() { return false }

// We want to avoid putting more in the visited map than we need to.
// For any possible reference cycle that might be encountered,
// hard(v1, v2) needs to return true for at least one of the types in the cycle,
// and it's safe and valid to get Value's internal pointer.
hard := func(v1, v2 Value) bool {
	switch v1.Kind() {
	case Pointer:
		if v1.typ.ptrdata == 0 {
			// not-in-heap pointers can't be cyclic.
			// At least, all of our current uses of runtime/internal/sys.NotInHeap
			// have that property. The runtime ones aren't cyclic (and we don't use
			// DeepEqual on them anyway), and the cgo-generated ones are
			// all empty structs.
			return false
		}
		fallthrough
	case Map, Slice, Interface:
		// Nil pointers cannot be cyclic. Avoid putting them in the visited map.
		return !v1.IsNil() && !v2.IsNil()
	}
	return false
}

if hard(v1, v2) {
	// For a Pointer or Map value, we need to check flagIndir,
	// which we do by calling the pointer method.
	// For Slice or Interface, flagIndir is always set,
	// and using v.ptr suffices.
	ptrval := func(v Value) unsafe.Pointer {
		switch v.Kind() {
		case Pointer, Map:
			return v.pointer()
		default:
			return v.ptr
		}
	}
	addr1 := ptrval(v1)
	addr2 := ptrval(v2)
	if uintptr(addr1) > uintptr(addr2) {
		// Canonicalize order to reduce number of entries in visited.
		// Assumes non-moving garbage collector.
		addr1, addr2 = addr2, addr1
	}

	// Short circuit if references are already seen.
	typ := v1.Type()
	v := visit{addr1, addr2, typ}
	if visited[v] {
		return true
	}

	// Remember for later.
	visited[v] = true
}

switch v1.Kind() {
case Array:
	for i := 0; i < v1.Len(); i++ {
		if !deepValueEqual(v1.Index(i), v2.Index(i), visited) {
			return false
		}
	}
	return true
case Slice:
	if v1.IsNil() != v2.IsNil() {
		return false
	}
	if v1.Len() != v2.Len() {
		return false
	}
	if v1.UnsafePointer() == v2.UnsafePointer() {
		return true
	}
	// Special case for []byte, which is common.
	if v1.Type().Elem().Kind() == Uint8 {
		return bytealg.Equal(v1.Bytes(), v2.Bytes())
	}
	for i := 0; i < v1.Len(); i++ {
		if !deepValueEqual(v1.Index(i), v2.Index(i), visited) {
			return false
		}
	}
	return true
case Interface:
	if v1.IsNil() || v2.IsNil() {
		return v1.IsNil() == v2.IsNil()
	}
	return deepValueEqual(v1.Elem(), v2.Elem(), visited)
case Pointer:
	if v1.UnsafePointer() == v2.UnsafePointer() {
		return true
	}
	return deepValueEqual(v1.Elem(), v2.Elem(), visited)
case Struct:
	for i, n := 0, v1.NumField(); i < n; i++ {
		if !deepValueEqual(v1.Field(i), v2.Field(i), visited) {
			return false
		}
	}
	return true
case Map:
	if v1.IsNil() != v2.IsNil() {
		return false
	}
	if v1.Len() != v2.Len() {
		return false
	}
	if v1.UnsafePointer() == v2.UnsafePointer() {
		return true
	}
	for _, k := range v1.MapKeys() {
		val1 := v1.MapIndex(k)
		val2 := v2.MapIndex(k)
		if !val1.IsValid() || !val2.IsValid() || !deepValueEqual(val1, val2, visited) {
			return false
		}
	}
	return true
case Func:
	if v1.IsNil() && v2.IsNil() {
		return true
	}
	// Can't do better than this:
	return false
case Int, Int8, Int16, Int32, Int64:
	return v1.Int() == v2.Int()
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
	return v1.Uint() == v2.Uint()
case String:
	return v1.String() == v2.String()
case Bool:
	return v1.Bool() == v2.Bool()
case Float32, Float64:
	return v1.Float() == v2.Float()
case Complex64, Complex128:
	return v1.Complex() == v2.Complex()
default:
	// Normal equality suffices
	return valueInterface(v1, false) == valueInterface(v2, false)
}

}