热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

TensorFlow使用Python自定义op和损失函数

TensorFlow使用Python自定义op和损失函数TensorFlow是静态图结构,即必须把所有的操作以及网络结构定义好(后来有了动态图功能,即EagerExecution)
TensorFlow使用Python自定义op和损失函数

TensorFlow是静态图结构,即必须把所有的操作以及网络结构定义好(后来有了动态图功能,即Eager Execution ),在没有用tf.Session().run接口填充值之前是没有实际值的。因此,在网络搭建的时候,是不能对tensor进行判值操作的,即不能插入if…else…之类的代码。这相较于numpy array,Tensorflow中对tensor的操作接口灵活性并没有那么高,为了扩展Tensorflow程序的灵活性,Tensorflow提供了tf.py_func接口。

如果使用tf.py_func调用了非TensorFlow原生的接口,使用第三方库定义某个功能时,很容易出现如下错误:

ValueError: No gradients provided for any variable, check your graph for ops that do not support gradients, between variables [“”, “”] and loss Tensor(“Mean:0”, shape=(), dtype=float32).

出现这个原因,本质上来说,就是我们利用第三方库自定义层,相关变量没有计算梯度!我们知道网络需要训练,每一层都需要定义计算前向和反向转播的,若采用TensorFlow自带的OP,是没有问题,因为Google以及实现前向和反向的过程。而采用第三方库时,只是实现了前向转播,而反向转播计算过程,我们是没有定义,所以就出现No gradients provided for any variable的错误!

如果你想想TensorFlow提供API一样,实现前向和反向转播的计算,可以参考两种方法:

(1)C++层自定义OP:基本流程:注册op,实现op,创建python接口,实现op梯度计算(如果不需要求导也可以直接pass掉,实现可以在python端也可以用py_func去包装其他python函数,也可以再写一个C++ op来专门计算梯度),测试等。这部分可以参考:

https://blog.csdn.net/u012436149/article/details/73737299 

https://www.zhihu.com/question/67352230 

https://zhuanlan.zhihu.com/p/34169502 

(2)Python层自定义OP:这个方法需要使用tf.py_func()调用第三方库实现前向计算过程,使用tf.RegisterGradient注册梯度反向传播函数实现反向转播计算过程。该方法是我比较推荐的,相比第一种方法,简单很多了,对于C++不是很熟悉的小朋友来说,在Python上自定义OP再好不过了!

目录

TensorFlow自定义op和Python损失函数

1.线性回归

1.1均方误差tf.reduce_mean(tf.square())

1.2 自定义均方误差

2. 出现No gradients provided for any variable的原因分析

3. 自定义损失函数

3.1@tf.RegisterGradient修饰器

3.2 gradient_override_map

3.3 自定义梯度反向传播函数

3.4 完整代码: 

4. 使用tf.RegisterGradient函数

4.1 tf.RegisterGradient()函数

4.2 完整的代码:

1.线性回归

先看一个线性回归的列子:https://www.cnblogs.com/selenaf/p/9102398.html

对于直线y=Wx+b,随机生成一些加入噪声的数据点,如下图所示。我们可以让TensorFlow建立线性回归模型,通过拟合这些数据去学习W和b的值。

《TensorFlow使用Python自定义op和损失函数》

1.1均方误差tf.reduce_mean(tf.square())

损失函数可以选择均方误差,可以直接调用TensorFlow的tf.reduce_mean(tf.square())实现均方差损失,这样完整的训练代码可如下实现:

#! /usr/bin/env python
# coding=utf-8
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
print(tf.__version__)
def gen_data(w,b,num_points):
'''
y=wx+b
:param w:
:param b:
:param num_points:
:return:
'''
vectors_set=[]
x_data=[]
y_data=[]
for i in range(num_points):
x1=np.random.normal(0.0,0.55) #横坐标,进行随机高斯处理化,以0为均值,以0.55为标准差
y1=x1*w+b+np.random.normal(0.0,0.03) #纵坐标,数据点在y1=x1*0.1+0.3上小范围浮动
vectors_set.append([x1,y1])
x_data=[v[0] for v in vectors_set]
y_data=[v[1] for v in vectors_set]
plt.scatter(x_data,y_data,c='r')
plt.show()
x_data=np.array(x_data,dtype=np.float32)
y_data=np.array(y_data,dtype=np.float32)
return x_data,y_data
def train_linear_regression(x_data,y_data,max_iterate):
'''
:param x_data:
:param y_data:
:param max_iterate: 最大迭代次数
:return:
'''
print("x_data.shape:{}".format(x_data.shape))
print("y_data.shape:{}:".format(y_data.shape))
# 定义线性回归模型
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='W') # 生成1维的W矩阵,取值是[-1,1]之间的随机数
b = tf.Variable(tf.zeros([1]), name='b') # 生成1维的b矩阵,初始值是0
y = W * x_data + b # 经过计算得出预估值y
# 定义计算图
graph = tf.get_default_graph()
# 定义均方误差
loss = tf.reduce_mean(tf.square(y - y_data), name='loss') # 以预估值y和实际值y_data之间的均方误差作为损失
# 定义优化器
optimizer = tf.train.GradientDescentOptimizer(0.1) # 采用梯度下降法来优化参数 学习率为0.5
train = optimizer.minimize(loss, name='train') # 训练的过程就是最小化这个误差值
# 训练
with tf.Session(graph=graph) as sess:
init = tf.global_variables_initializer()
sess.run(init)
for step in range(max_iterate): # 执行20次训练
_,pre_W,pre_b,pre_loss=sess.run([train,W,b,loss])
print("step:{},W={},b={},loss={}".format(step+1,pre_W,pre_b,pre_loss))
if __name__=='__main__':
w=0.1
b=0.3
num_points=1000
max_iterate=1000
x_data, y_data=gen_data(w, b, num_points)
train_linear_regression(x_data, y_data, max_iterate)

《TensorFlow使用Python自定义op和损失函数》

step:1,W=[0.33111742],b=[0.05976159],loss=0.10794320702552795
step:2,W=[0.31746817],b=[0.10756931],loss=0.07375720143318176
step:3,W=[0.3046297],b=[0.14581403],loss=0.05137966573238373
step:4,W=[0.29255316],b=[0.17640844],loss=0.03661665320396423
step:5,W=[0.28119272],b=[0.20088267],loss=0.02677750028669834
step:6,W=[0.2705055],b=[0.22046085],loss=0.020134398713707924
step:7,W=[0.2604512],b=[0.23612225],loss=0.015576418489217758
step:8,W=[0.25099206],b=[0.2486503],loss=0.01238801795989275
step:9,W=[0.24209262],b=[0.25867173],loss=0.010107231326401234
......
......
step:995,W=[0.10031797],b=[0.29867724],loss=0.0008959544938988984
step:996,W=[0.10031797],b=[0.29867724],loss=0.0008959544938988984
step:997,W=[0.10031797],b=[0.29867724],loss=0.0008959544938988984
step:998,W=[0.10031797],b=[0.29867724],loss=0.0008959544938988984
step:999,W=[0.10031797],b=[0.29867724],loss=0.0008959544938988984
step:1000,W=[0.10031797],b=[0.29867724],loss=0.0008959544938988984

通过迭代1000次,模型可以很好的拟合数据,并且学习到权值W=[0.10031797],b=[0.29867724],这与设定w=0.1 b=0.3的差异很小了

1.2 自定义均方误差

上面的训练代码,损失函数是直接调用TensorFlow的tf.reduce_mean(tf.square())实现均方差损失,现在问题来呢?我们可否不调用TensorFlow的 API接口,自己使用第三方的Python库自定义TensorFlow的损失函数,于是,我们尝试使用Python math库定义一个平方差square_loss:

def square_loss(array1,array2):
'''
使用math自定义平方损失函数:Square loss=(x-y)^2
:param array1: input x
:param array2: input y
:return:
'''
# loss=np.square(array1-array2)
square=[]
for a1,a2 in zip(array1,array2):
s=math.pow(a1-a2,2)
square.append(s)
loss=np.array(square,dtype=np.float32)
return loss

 说明:这里square_loss是使用math的Python包实现平方差,实质上一种更简单的方法,是使用Numpy执行loss=np.square(array1-array2)即可,这两种方式是等价,之所以没有用Numpy,那是因为TensorFlow的tensor变量很多都支持Nump的计算,很难体现出博客的用意:使用第三方的Python库自定义TensorFlow的损失函数。当然,实际开发,还是建议使用Numpy实现各种复杂的计算。

由于使用第三方的Python库实现的函数,这需要借助TF的tf.py_func中传入自定义的loss函数

tf.py_func的用法:请参考:https://www.tensorflow.org/api_docs/python/tf/py_func

tf.py_func( func,inp,Tout,stateful=True,name=None)前三个参数说明:

    第一个参数func,也是最重要的,是一个用户自定制的函数,输入numpy array,输出也是numpy array,在该函数中,可以自由使用np.操作。

   第二个参数inp,是func函数接收的输入,是一个列表

   第三个参数Tout,指定了func函数返回的numpy array转化成tensor后的格式,如果是返回个值,就是一个列表或元组;如果只有个返回值,就是一个单独的dtype类型(当然也可以用列表括起来)。

于是,我把训练的代码的loss定义如下:

# 定义均方误差
# loss = tf.reduce_mean(tf.square(y - y_data), name='loss') # 以预估值y和实际值y_data之间的均方误差作为损失
# loss = tf.reduce_mean(square_loss(y,y_data))
loss = tf.reduce_mean(tf.py_func(square_loss, inp=[y, y_data], Tout=tf.float32))

好了,定义完成,Run,终于出现了我想要说的错误:

ValueError: No gradients provided for any variable, check your graph for ops that do not support gradients, between variables [“”, “”] and loss Tensor(“Mean:0”, shape=(), dtype=float32). 

2. 出现No gradients provided for any variable的原因分析

出现这个原因,本质上来说,就是我们利用第三方库自定义的损失或者其他层,相关变量没有计算梯度!我们知道网络需要训练,每一层都需要定义和计算前向和反向转播的,若采用TensorFlow自带的OP,是没有问题,因为Google以及实现前向和反向的过程。而采用第三方库时,只是实现了前向转播,而反向转播计算过程,我们是没有定义,所以就出现No gradients provided for any variable的错误了!

3. 自定义损失函数

在自定义损失函数前,先介绍两个TensorFlow的函数tf.RegisterGradient和 tf.Graph.gradient_override_map

3.1@tf.RegisterGradient修饰器

@tf.RegisterGradient修饰符在定义一个新的 op 类型时使用。对于具有 m 个输入和 n 个输出的运算,梯度函数是一个采用原始的 Operation 和 n Tensor 对象(表示与 op 的每个输出相关的梯度),并返回 m Tensor 对象(表示相对于 op 的每个输入的部分梯度)的函数。

例如,假设该类型的”Sub”操作需要两个输入 x 和 y,并返回一个单一的输出 x – y,则以下梯度函数将被注册:

@tf.RegisterGradient("Sub")
def _sub_grad(unused_op, grad):
return grad, tf.negative(grad)

修饰符参数 op_type 是操作的字符串类型。这对应于定义操作的原始 OpDef. name 字段。 

参考:https://tensorflow.google.cn/api_docs/python/tf/RegisterGradient

3.2 gradient_override_map

 tf.Graph.gradient_override_map(op_type_map):返回一个覆盖梯度函数的上下文管理器,此管理器用于覆盖ops的梯度函数。通过这个管理器,我们可以针对自定义operation,使用自己的gradient函数。例如

# 先注册一个gradient函数
@tf.RegisterGradient("CustomSquare")
def _custom_square_grad(op, grad):
  # ...
with tf.Graph().as_default() as g:
  c = tf.constant(5.0)
  s_1 = tf.square(c) # 使用tf.square默认的gradient
  with g.gradient_override_map({"Sqaure": "CustomSquare"}):
    s_2 = tf.square(s_2): # 使用自定义的_custom_square_grad函数来计算s_2的梯度

3.3 自定义梯度反向传播函数

使用TensorFlow的修饰器@tf.RegisterGradient(“LossGradient”),定义一个平方差损失square_loss_grad函数的梯度计算过程:

平方差损失:《TensorFlow使用Python自定义op和损失函数》

对x求偏导:《TensorFlow使用Python自定义op和损失函数》

对 y求偏导:《TensorFlow使用Python自定义op和损失函数》

对应的Python代码如下: 


@tf.RegisterGradient("LossGradient")
def square_loss_grad(op, grad):
'''
使用修饰器,建立梯度反向传播函数。其中op.input包含输入值、输出值,grad包含上层传来的梯度
:param op:
:param grad:
:return:
'''
x = op.inputs[0]
y = op.inputs[1]
# 计算平方损失的梯度:loss=(x-y)^2
grad_x = 2 * grad * (x - y) # 对x求导:grad_x=2(x-y)
grad_y = tf.negative(2 * grad * (x - y)) # 对y求导:grad_y=-2(x-y)
return grad_x, grad_y

然后在调用square_loss时插入tf.get_default_graph().gradient_override_map({“PyFunc”: ‘LossGradient’}) 

def my_loss(y, y_data):
with tf.get_default_graph().gradient_override_map({"PyFunc": 'LossGradient'}):
loss=tf.py_func(square_loss, inp=[y, y_data], Tout=tf.float32)
return loss

 最后训练代码的loss修改如下:

# 定义均方误差
# loss = tf.reduce_mean(tf.square(y - y_data), name='loss') # 以预估值y和实际值y_data之间的均方误差作为损失
# loss = tf.reduce_mean(square_loss(y,y_data))
# loss = tf.reduce_mean(tf.py_func(square_loss, inp=[y, y_data], Tout=tf.float32))
loss=tf.reduce_mean(my_loss(y,y_data))

3.4 完整代码: 

#! /usr/bin/env python
# coding=utf-8
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import math
print(tf.__version__)
def gen_data(w,b,num_points):
'''
y=wx+b
:param w:
:param b:
:param num_points:
:return:
'''
vectors_set=[]
x_data=[]
y_data=[]
for i in range(num_points):
x1=np.random.normal(0.0,0.55) #横坐标,进行随机高斯处理化,以0为均值,以0.55为标准差
y1=x1*w+b+np.random.normal(0.0,0.03) #纵坐标,数据点在y1=x1*0.1+0.3上小范围浮动
vectors_set.append([x1,y1])
x_data=[v[0] for v in vectors_set]
y_data=[v[1] for v in vectors_set]
plt.scatter(x_data,y_data,c='r')
plt.show()
x_data=np.array(x_data,dtype=np.float32)
y_data=np.array(y_data,dtype=np.float32)
return x_data,y_data
def square_loss(array1,array2):
'''
使用math自定义平方损失函数:Square loss=(x-y)^2
:param array1: input x
:param array2: input y
:return:
'''
# loss=np.square(array1-array2)
square=[]
for a1,a2 in zip(array1,array2):
s=math.pow(a1-a2,2)
square.append(s)
loss=np.array(square,dtype=np.float32)
return loss
@tf.RegisterGradient("LossGradient")
def square_loss_grad(op, grad):
'''
使用修饰器,建立梯度反向传播函数。其中op.input包含输入值、输出值,grad包含上层传来的梯度
:param op:
:param grad:
:return:
'''
x = op.inputs[0]
y = op.inputs[1]
# 计算平方损失的梯度:loss=(x-y)^2
grad_x = 2 * grad * (x - y) # 对x求导:grad_x=2(x-y)
grad_y = tf.negative(2 * grad * (x - y)) # 对y求导:grad_y=-2(x-y)
return grad_x, grad_y
def my_loss(y, y_data):
with tf.get_default_graph().gradient_override_map({"PyFunc": 'LossGradient'}):
loss=tf.py_func(square_loss, inp=[y, y_data], Tout=tf.float32)
return loss
def train_linear_regression(x_data,y_data,max_iterate):
'''
:param x_data:
:param y_data:
:param max_iterate: 最大迭代次数
:return:
'''
print("x_data.shape:{}".format(x_data.shape))
print("y_data.shape:{}:".format(y_data.shape))
# 定义线性回归模型
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='W') # 生成1维的W矩阵,取值是[-1,1]之间的随机数
b = tf.Variable(tf.zeros([1]), name='b') # 生成1维的b矩阵,初始值是0
y = W * x_data + b # 经过计算得出预估值y
# 定义计算图
graph = tf.get_default_graph()
# 定义均方误差
# loss = tf.reduce_mean(tf.square(y - y_data), name='loss') # 以预估值y和实际值y_data之间的均方误差作为损失
# loss = tf.reduce_mean(square_loss(y,y_data))
# loss = tf.reduce_mean(tf.py_func(square_loss, inp=[y, y_data], Tout=tf.float32))
loss=tf.reduce_mean(my_loss(y,y_data))
# 定义优化器
optimizer = tf.train.GradientDescentOptimizer(0.1) # 采用梯度下降法来优化参数 学习率为0.5
train = optimizer.minimize(loss, name='train') # 训练的过程就是最小化这个误差值
# 训练
with tf.Session(graph=graph) as sess:
init = tf.global_variables_initializer()
sess.run(init)
for step in range(max_iterate): # 执行20次训练
_,pre_W,pre_b,pre_loss=sess.run([train,W,b,loss])
print("step:{},W={},b={},loss={}".format(step+1,pre_W,pre_b,pre_loss))
if __name__=='__main__':
w=0.1
b=0.3
num_points=1000
max_iterate=1000
x_data, y_data=gen_data(w, b, num_points)
train_linear_regression(x_data, y_data, max_iterate)
4. 使用tf.RegisterGradient函数

4.1 tf.RegisterGradient()函数

当然也可以不使用装饰器,TensorFlow提供了tf.RegisterGradient()函数,可以直接调用梯度函数


def py_func_grad(func, inp, Tout, stateful=True, name=None, grad=None):
'''
Custom py_func with gradient support
:param func: 前向传播函数
:param inp: func函数的输入参数
:param Tout: func函数的输出参数
:param stateful:
:param name:
:param grad: 反向转播函数
:return:
'''
# Need to generate a unique name to avoid duplicates:
rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+8))
tf.RegisterGradient(rnd_name)(grad)
g = tf.get_default_graph()
with g.gradient_override_map({
"PyFunc": rnd_name,
"PyFuncStateless": rnd_name}):
return tf.py_func(func, inp, Tout, stateful=stateful, name=name)

  最后训练代码的loss修改如下:

# 定义均方误差
# loss = tf.reduce_mean(tf.square(y - y_data), name='loss') # 以预估值y和实际值y_data之间的均方误差作为损失
# loss = tf.reduce_mean(square_loss(y,y_data))
# loss = tf.reduce_mean(tf.py_func(square_loss, inp=[y, y_data], Tout=tf.float32))
# loss=tf.reduce_mean(my_loss(y,y_data))
loss=tf.reduce_mean(py_func_grad(square_loss, inp=[y,y_data], Tout=tf.float32, grad=square_loss_grad))

4.2 完整的代码:

#! /usr/bin/env python
# coding=utf-8
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
import math
print(tf.__version__)
def gen_data(w,b,num_points):
'''
y=wx+b
:param w:
:param b:
:param num_points:
:return:
'''
vectors_set=[]
x_data=[]
y_data=[]
for i in range(num_points):
x1=np.random.normal(0.0,0.55) #横坐标,进行随机高斯处理化,以0为均值,以0.55为标准差
y1=x1*w+b+np.random.normal(0.0,0.03) #纵坐标,数据点在y1=x1*0.1+0.3上小范围浮动
vectors_set.append([x1,y1])
x_data=[v[0] for v in vectors_set]
y_data=[v[1] for v in vectors_set]
plt.scatter(x_data,y_data,c='r')
plt.show()
x_data=np.array(x_data,dtype=np.float32)
y_data=np.array(y_data,dtype=np.float32)
return x_data,y_data
def square_loss(array1,array2):
'''
使用math自定义平方损失函数:Square loss=(x-y)^2
:param array1: input x
:param array2: input y
:return:
'''
# loss=np.square(array1-array2)
square=[]
for a1,a2 in zip(array1,array2):
s=math.pow(a1-a2,2)
square.append(s)
loss=np.array(square,dtype=np.float32)
return loss
def square_loss_grad(op, grad):
'''
使用修饰器,建立梯度反向传播函数。其中op.input包含输入值、输出值,grad包含上层传来的梯度
:param op:
:param grad:
:return:
'''
x = op.inputs[0]
y = op.inputs[1]
# 计算平方损失的梯度:loss=(x-y)^2
grad_x = 2 * grad * (x - y) # 对x求导:grad_x=2(x-y)
grad_y = tf.negative(2 * grad * (x - y)) # 对y求导:grad_y=-2(x-y)
return grad_x, grad_y
def py_func_grad(func, inp, Tout, stateful=True, name=None, grad=None):
'''
Custom py_func with gradient support
:param func: 前向传播函数
:param inp: func函数的输入参数
:param Tout: func函数的输出参数
:param stateful:
:param name:
:param grad: 反向转播函数
:return:
'''
# Need to generate a unique name to avoid duplicates:
rnd_name = 'PyFuncGrad' + str(np.random.randint(0, 1E+8))
tf.RegisterGradient(rnd_name)(grad)
g = tf.get_default_graph()
with g.gradient_override_map({
"PyFunc": rnd_name,
"PyFuncStateless": rnd_name}):
return tf.py_func(func, inp, Tout, stateful=stateful, name=name)
def train_linear_regression(x_data,y_data,max_iterate):
'''
:param x_data:
:param y_data:
:param max_iterate: 最大迭代次数
:return:
'''
print("x_data.shape:{}".format(x_data.shape))
print("y_data.shape:{}:".format(y_data.shape))
# 定义线性回归模型
W = tf.Variable(tf.random_uniform([1], -1.0, 1.0), name='W') # 生成1维的W矩阵,取值是[-1,1]之间的随机数
b = tf.Variable(tf.zeros([1]), name='b') # 生成1维的b矩阵,初始值是0
y = W * x_data + b # 经过计算得出预估值y
# 定义计算图
graph = tf.get_default_graph()
# 定义均方误差
# loss = tf.reduce_mean(tf.square(y - y_data), name='loss') # 以预估值y和实际值y_data之间的均方误差作为损失
# loss = tf.reduce_mean(square_loss(y,y_data))
# loss = tf.reduce_mean(tf.py_func(square_loss, inp=[y, y_data], Tout=tf.float32))
# loss=tf.reduce_mean(my_loss(y,y_data))
loss=tf.reduce_mean(py_func_grad(square_loss, inp=[y,y_data], Tout=tf.float32, grad=square_loss_grad))
# 定义优化器
optimizer = tf.train.GradientDescentOptimizer(0.1) # 采用梯度下降法来优化参数 学习率为0.5
train = optimizer.minimize(loss, name='train') # 训练的过程就是最小化这个误差值
# 训练
with tf.Session(graph=graph) as sess:
init = tf.global_variables_initializer()
sess.run(init)
for step in range(max_iterate): # 执行20次训练
_,pre_W,pre_b,pre_loss=sess.run([train,W,b,loss])
print("step:{},W={},b={},loss={}".format(step+1,pre_W,pre_b,pre_loss))
if __name__=='__main__':
w=0.1
b=0.3
num_points=1000
max_iterate=1000
x_data, y_data=gen_data(w, b, num_points)
train_linear_regression(x_data, y_data, max_iterate)

 


推荐阅读
  • 开机自启动的几种方式
    0x01快速自启动目录快速启动目录自启动方式源于Windows中的一个目录,这个目录一般叫启动或者Startup。位于该目录下的PE文件会在开机后进行自启动 ... [详细]
  • 目录预备知识导包构建数据集神经网络结构训练测试精度可视化计算模型精度损失可视化输出网络结构信息训练神经网络定义参数载入数据载入神经网络结构、损失及优化训练及测试损失、精度可视化qu ... [详细]
  • 2020年9月15日,Oracle正式发布了最新的JDK 15版本。本次更新带来了许多新特性,包括隐藏类、EdDSA签名算法、模式匹配、记录类、封闭类和文本块等。 ... [详细]
  • This feature automatically validates new regions using the AWS SDK, ensuring compatibility and accuracy. ... [详细]
  • Ihavetwomethodsofgeneratingmdistinctrandomnumbersintherange[0..n-1]我有两种方法在范围[0.n-1]中生 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 您的数据库配置是否安全?DBSAT工具助您一臂之力!
    本文探讨了Oracle提供的免费工具DBSAT,该工具能够有效协助用户检测和优化数据库配置的安全性。通过全面的分析和报告,DBSAT帮助用户识别潜在的安全漏洞,并提供针对性的改进建议,确保数据库系统的稳定性和安全性。 ... [详细]
  • PTArchiver工作原理详解与应用分析
    PTArchiver工作原理及其应用分析本文详细解析了PTArchiver的工作机制,探讨了其在数据归档和管理中的应用。PTArchiver通过高效的压缩算法和灵活的存储策略,实现了对大规模数据的高效管理和长期保存。文章还介绍了其在企业级数据备份、历史数据迁移等场景中的实际应用案例,为用户提供了实用的操作建议和技术支持。 ... [详细]
  • 针对MySQL Undo空间满载及Oracle Undo表空间溢出的问题,本文详细探讨了其原因与解决策略。首先,通过启动SQL*Plus并以SYS用户身份登录数据库,查询当前数据库的UNDO表空间名称,确认当前状态。接着,分析导致Undo空间满载的常见原因,如长时间运行的事务、频繁的更新操作等,并提出相应的解决方案,包括调整Undo表空间大小、优化事务管理、定期清理历史数据等。最后,结合实际案例,提供具体的实施步骤和注意事项,帮助DBA有效应对这些问题。 ... [详细]
  • 2012年9月12日优酷土豆校园招聘笔试题目解析与备考指南
    2012年9月12日,优酷土豆校园招聘笔试题目解析与备考指南。在选择题部分,有一道题目涉及中国人的血型分布情况,具体为A型30%、B型20%、O型40%、AB型10%。若需确保在随机选取的样本中,至少有一人为B型血的概率不低于90%,则需要选取的最少人数是多少?该问题不仅考察了概率统计的基本知识,还要求考生具备一定的逻辑推理能力。 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
  • Python 实战:异步爬虫(协程技术)与分布式爬虫(多进程应用)深入解析
    本文将深入探讨 Python 异步爬虫和分布式爬虫的技术细节,重点介绍协程技术和多进程应用在爬虫开发中的实际应用。通过对比多进程和协程的工作原理,帮助读者理解两者在性能和资源利用上的差异,从而在实际项目中做出更合适的选择。文章还将结合具体案例,展示如何高效地实现异步和分布式爬虫,以提升数据抓取的效率和稳定性。 ... [详细]
  • MySQL索引详解及其优化策略
    本文详细解析了MySQL索引的概念、数据结构及管理方法,并探讨了如何正确使用索引以提升查询性能。文章还深入讲解了联合索引与覆盖索引的应用场景,以及它们在优化数据库性能中的重要作用。此外,通过实例分析,进一步阐述了索引在高读写比系统中的必要性和优势。 ... [详细]
  • 在CodeIgniter框架中集成新库文件的过程中,我遇到了一些困惑。具体来说,在跟随nettuts的认证教程时,对于在Welcome控制器中添加的构造函数代码,特别是关于Session的验证部分,我感到不太理解。这部分内容涉及如何确保Session已经初始化并具备相应的功能,这对于实现用户认证至关重要。为了更好地掌握这一知识点,我计划深入研究CodeIgniter的官方文档,并参考更多相关资源,以确保能够正确地集成和使用新库文件。 ... [详细]
author-avatar
18岁的淡淡淡色彩
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有