如何创建一个百分百懂你的产品推荐系统 | 深度教程(附代码详解)

(图片由AI科技大本营付费下载自视觉中国)
来源 | 读芯术(ID:AI_Discovery)
你也许每天都会逛一逛电子商务网站,或者从博客、新闻和媒体出版物上阅读大量文章。浏览这些东西的时候,最令读者或者用户烦恼的事情是什么呢?
——有太多的东西可以看,反而会经常看不到自己正在搜索的东西。
是的,网上有太多的信息和文章,用户需要一种方式来简化他们的发现之旅。如果你在经营一家电子商务网站或博客,你也许会问:有这个必要吗?
嗯……你听过漏斗吗?
用户所用的漏斗越小,产品的转换就越大。这是用户体验的基本原则。所以,如果减少步骤的数量可以增加网站页面的浏览量甚至是收入,为什么不这么做呢?
推荐系统如何提供帮助?
简单来说,推荐系统就是一个发现系统,该系统可通过分析数据向用户提供推荐。不需要用户去专门搜索,系统自动带来推荐商品。
这听起来像是魔法。亚马逊和Netflix几十年前就开始使用这种魔法了。一打开Spotify,它就已经为用户提供了一个推荐歌单(这种深度个性化推荐服务叫作Discover Weekly)。
深入了解推荐系统
一般来说,我们所知的推荐系统有两种——当然并不是所有的人都知道。
1. 基于内容的推荐系统
这类推荐系统很容易被我们的大脑消化,而且不会出现短路或爆炸的迹象。例如,你是一个狂热的小说迷,喜欢阿加莎·克里斯蒂的《无人生还》,并从网上书店买了这本书。那么,当你下次再打开网站时,网上书店就会给你推荐《ABC谋杀案》。
为什么呢?
因为它们都是阿加莎·克里斯蒂的作品。因此,基于内容的推荐模型会向你推荐这本书。就是这么简单!那就来用一用吧!
等等……
虽然这种基于内容的推荐很容易被我们的大脑消化,看起来也很简单,但它无法预测用户的真实行为。例如,你不喜欢侦探赫丘里·波罗,但喜欢阿加莎·克里斯蒂小说中的其他侦探。在这种情况下,网站就不应该向你推荐《ABC谋杀案》。
2. 协同过滤推荐系统
这种类型的推荐系统克服了上面的问题。本质上,该系统记录了用户在网站上的所有交互,并基于这些记录提出建议。
它是什么原理呢?请看下面的场景:
这里有两个用户,用户A和用户B。
用户A购买了商品1用户A购买了商品2用户A购买了商品3用户B购买了商品1用户B购买了商品3
那么协同过滤系统将会向用户B推荐商品2,因为有另外一个用户也购买了商品1和商品3,同时还购买了商品2。
你也许会说,得了吧,他们可能是偶然才一起买了那些巧合的商品。
但是,如果有100个用户都与用户A有相同的购买行为呢?这就是所谓的群众的力量。
那么,你还在等什么呢?让我们开始在你的生产环境中创建协同过滤推荐系统吧!等等,先别着急!
虽然这个系统性能极佳,但在尝试创建可用于生产的系统时,它还存在几个严重问题。
协同过滤推荐系统的不足
1. 它不知道用户的购物习惯。基于内容的推荐系统会根据用户的购物记录推荐相似商品,与此相反,协同过滤推荐系统的推荐并不是基于相似性。如果你关心这一问题的话,解决方案就是将两种方法混合起来,结合使用。
2. 因为需要存储用户项矩阵,所以系统需要大量的硬件资源。假设你的电子商务网站有10万用户;与此同时,你的网站提供1万种产品。在这种情况下,你将需要10000 x 100000的矩阵,每个元素包含4个字节的整数。是的,光是存储矩阵,不做其他事,你就需要4GB的内存。
3. “冷启动”(冰冷的开始),该系统并不会为新用户带来好处,因为系统并不了解新用户。
4. 不变性。如果用户没有在网站上进行搜索或购物,系统的推荐将一成不变。于是用户就会认为网站上没有什么新鲜东西,从而退出网站。
通过混合使用两种推荐系统可以轻易解决第1个问题,然而,其他问题仍然令人头痛。本文的目的就是解决第2、第3和第4个问题。
让我们开始吧!
使推荐系统可用于生产的终极指南
如何解决这些问题?机器本身存在限制,而且就算是根据常识,也不可能仅为小小的需求就部署一个巨大的服务器。
推荐下面这本书:
Ted Dunning 和Ellen Friedman的《实用性机器学习》
这本书告诉我们,对于一个可用于生产的系统,你不需要指望它在任何方面都具备最高精度。在实际的用例中,一个有些不准确但又可以接受的方法,通常是最有效的。
关于如何做到这一点,最有趣的部分是:
1. 对通用推荐指标进行批量计算。
2. 实时查询,不使用用户-商品矩阵,而是获取用户的最新交互并向系统查询。
下面我们边构建系统边解释。
Python的推荐系统
为什么选择python? 因为python的语言简单易学,只需要几个小时就能理解它的语法。
for item in the_bag: print(item)
通过上面代码,你可以打印包里的所有项。可访问Python官网,根据操作系统下载并安装相应安装包。
https://www.python.org/downloads/
本教程需要用到以下几个安装包。
pip install numpy
pip install scipy
pip install pandas
pip install jupyter
pip install requests
Numpy和Scipy是处理数学计算的python包,建构矩阵时需要用到它们。Pandas 用于数据处理。Requests用于http调用。Jupyter是一个可以交互运行python代码的网络应用程序。
输入Jupyter Notebook,你会看到如下界面

在提供的单元格上编写代码,代码将以交互方式运行。
开始之前需要几个工具。
1. Elasticsearch(弹性搜索)。这是一个开源搜索引擎,可以帮助快速搜索到文档。这个工具可用于保存计算指标,以便实时查询。
2. Postman。这是一个API开发工具,可用来模拟弹性搜索中的查询,因为弹性搜索可以通过http访问。
下载并安装这两个工具,接着就可以开始了。
先来看看Kaggle中的数据集:电子商务网站行为数据集,下载并提取Jupyter 笔记本目录中的数据。
http://www.baidu.com/link?url=-uZgHHgYJmRlBX5WL_ufkLSb0S5eXU0j43iPMLh3XNtXbLq5uNoqe3Oje7AUt0PK
在这些文件中,本教程只需要用到events.csv。该文件由用户对电子商务网站上的商品进行的数百万次操作组成。
开始探索数据吧!
import pandas as pd
import numpy as np
将输入写在Jupyter Notebook上,就可以开始了。
df = pd.read_csv('events.csv')
df.shape
它会输出(2756101,5),这意味着你有270万行和5列。
让我们来看看
df.head()
它有5栏:
1. 时间戳(Timestamp),事件的时间戳
2. 访问者ID(Visitorid),用户的身份
3. 商品ID(Itemid), 商品的名称
4. 事件(Event), 事件
5. 交易ID(Transactionid),如果事件是交易,则为交易ID
下面检查一下,哪些事件是可用的
df.event.unique()
你将获得三个事件:浏览、添加到购物车和交易。
你可能嫌麻烦,不想处理所有事件,所以本教程中只需处理交易。所以,我们只过滤交易。
trans = df[df['event'] == 'transaction']
trans.shape
它将输出(22457, 5),也就是说你将有22457个交易数据可以处理。这对新手来说已经足够了。
下面来进一步看看数据:
visitors = trans['visitorid'].unique()
items = trans['itemid'].unique() print(visitors.shape)
print(items.shape)
你将获得11719个独立访问者和12025个独立商品。
创建一个简单而有效的推荐系统,经验之谈是在不损失质量的情况下对数据进行抽样。这意味着,对于每个用户,你只需获取50个最新交易数据,却仍然可以获得想要的质量,因为顾客行为会随着时间的推移而改变。
trans2 = trans.groupby(['visitorid']).head(50)
trans2.shape
现在你只有19939笔交易。这意味着2000笔左右的交易已经过时。由于访问者ID和商品ID是一长串的数字,你很难记住每个ID。
trans2['visitors'] = trans2['visitorid'].apply(lambda x : np.argwhere(visitors == x)[0][0])
trans2['items'] = trans2['itemid'].apply(lambda x : np.argwhere(items == x)[0][0]) trans2
你需要其他基于0的索引列。如以下界面所示:
这样更加清晰。接下来的所有步骤只需使用访问者和商品栏。
下一步:创建用户-商品矩阵
噩梦来了……一共有11719个独立访问者和12025个商品,所以需要大约500MB的内存来存储矩阵。
稀疏矩阵(Sparse matrix)这时候就派上用场了。稀疏矩阵是大多数元素为零的矩阵。这是有意义的,因为不可能所有的用户都购买所有的商品,很多连接都将为零。
from scipy.sparse import csr_matrix
Scipy很有用。
occurences = csr_matrix((visitors.shape[0], items.shape[0]), dtype='int8') def set_occurences(visitor, item): occurences[visitor, item] += 1 trans2.apply(lambda row: set_occurences(row['visitors'], row['items']), axis=1) occurences
对数据中的每一行应用set_occurences函数。会输出如下结果:
<11719x12025 sparse matrix of type '<class 'numpy.int8'>'
with 18905 stored elements in Compressed Sparse Row format>
在矩阵的1.4亿个单元格中,只有18905个单元格是用非零数据填充的。
所以,实际上只需要把这18905个值存储到内存中,效率就能提高99.99%。
但稀疏矩阵有一个缺点,想要实时检索数据的话,需要很大的计算量。所以,到这里还没有结束。
共现矩阵
下面建构一个商品-商品矩阵,其中每个元素表示用户同时购买两个商品的次数,我们称之为共现矩阵。要创建共现矩阵,你需要将共现矩阵的转置与自身做点积。有人试过在没有稀疏矩阵的情况下这样做,结果电脑死机了。所以,千万不要重蹈覆辙。
cooc = occurences.transpose().dot(occurences)
cooc.setdiag(0)
电脑立马输出了一个稀疏矩阵。setdiag函数将对角线设置为0,这意味着你不想计算商品1的值,而商品1的位置都在一起,因为它们是相同的项目。
异常行为
共现矩阵包含同时购买两种商品的次数。但也可能会存在一种商品,购买这种商品本身和用户的购物习惯没有任何关系,可能是限时抢购之类的商品。
在现实中,你想要捕捉的是真正的用户行为,而非像限时抢购那样非常规行为。为了消除这些影响,你需要对共现矩阵的得分进行扣除。
Ted Dunnings在前一本书中提出了一种算法,叫做对数似然比(Log-Likelihood Ratio, LLR)。
def xLogX(x): return x * np.log(x) if x != 0 else 0.0 def entropy(x1, x2=0, x3=0, x4=0): return xLogX(x1 + x2 + x3 + x4) - xLogX(x1) - xLogX(x2) - xLogX(x3) - xLogX(x4) def LLR(k11, k12, k21, k22): rowEntropy = entropy(k11 + k12, k21 + k22) columnEntropy = entropy(k11 + k21, k12 + k22) matrixEntropy = entropy(k11, k12, k21, k22) if rowEntropy + columnEntropy < matrixEntropy: return 0.0 return 2.0 * (rowEntropy + columnEntropy - matrixEntropy) def rootLLR(k11, k12, k21, k22): llr = LLR(k11, k12, k21, k22) sqrt = np.sqrt(llr) if k11 * 1.0 / (k11 + k12) < k21 * 1.0 / (k21 + k22): sqrt = -sqrt return sqrt
LLR函数计算的是A和B两个事件同时出现的可能性。参数有:
1.k11, 两个事件同时发生的次数
2.k12, 事件B 单独发生的次数
3.k21, 事件A单独发生的次数
4.k22, 事件A和事件B都没有发生的次数
现在计算LLR函数并将其保存到pp_score矩阵中。
row_sum = np.sum(cooc, axis=0).A.flatten()
column_sum = np.sum(cooc, axis=1).A.flatten()
total = np.sum(row_sum, axis=0) pp_score = csr_matrix((cooc.shape[0], cooc.shape[1]), dtype='double')
cx = cooc.tocoo()
for i,j,v in zip(cx.row, cx.col, cx.data): if v != 0: k11 = v k12 = row_sum[i] - k11 k21 = column_sum[j] - k11 k22 = total - k11 - k12 - k21 pp_score[i,j] = rootLLR(k11, k12, k21, k22)
对结果进行排序,使每种商品LLR得分最高的位于每行的第一列。
result = np.flip(np.sort(pp_score.A, axis=1), axis=1)
result_indices = np.flip(np.argsort(pp_score.A, axis=1), axis=1)
推荐系统的指标
结果矩阵中的第一项指标如果足够高的话,可以被视为该项的指标。来看一下其中的一个结果:
result[8456]
你会得到
array([15.33511076, 14.60017668, 3.62091635, ..., 0. , 0. , 0. ])
再看看指标
result_indices[8456]
你会得到
array([8682, 380, 8501, ..., 8010, 8009, 0], dtype=int64)
可以有把握地说,商品8682和商品380的LLR分数很高,可以作为商品8456的指标。而商品8501分数不是那么高,可能不能作为商品8456的指标。这意味着,如果有用户购买了商品8682和商品380,你可以向他推荐商品8456。
这很简单。但是,根据经验,你可能想给LLR分数施加一些限制,这样可以删除无关紧要的指标。
minLLR = 5
indicators = result[:, :50]
indicators[indicators < minLLR] = 0.0 indicators_indices = result_indices[:, :50] max_indicator_indices = (indicators==0).argmax(axis=1)
max = max_indicator_indices.max() indicators = indicators[:, :max+1]
indicators_indices = indicators_indices[:, :max+1]
现在,已经准备好将它们组合到弹性搜索中了,这样就可以实时查询推荐。
好了,现在可以把之前准备好的东西放到弹性搜索中了。
但是,请注意。如果你想用 /_create/<id> API一个个地添加数据,将会花费很长时间。你当然可以这么做,但是可能需要花费半个小时到一个小时才能把12025个商品转移到弹性搜索中。
那怎么解决这个问题呢?
批量更新
幸运的是,弹性搜索拥有批量API,可以轻松地同时发送多个文档。因此,创建一个新索引(items2),让我们来尝试一下:
actions = []
for i in range(indicators.shape[0]): length = indicators[i].nonzero()[0].shape[0] real_indicators = items[indicators_indices[i, :length]].astype("int").tolist() id = items[i] action = { "index" : { "_index" : "items2", "_id" : str(id) } } data = { "id": int(id), "indicators": real_indicators } actions.append(json.dumps(action)) actions.append(json.dumps(data)) if len(actions) == 200: actions_string = "\n".join(actions) + "\n" actions = [] url = "http://127.0.0.1:9200/_bulk/" headers = { "Content-Type" : "application/x-ndjson" } requests.post(url, headers=headers, data=actions_string)if len(actions) > 0: actions_string = "\n".join(actions) + "\n" actions = [] url = "http://127.0.0.1:9200/_bulk/" headers = { "Content-Type" : "application/x-ndjson" } requests.post(url, headers=headers, data=actions_string)
瞧,只需要几秒钟就能完成。在Postman中点击这个API:127.0.0.1:9200/items2/_count,你就存储了数据。
{ "count": 12025, "_shards": { "total": 1, "successful": 1, "skipped": 0, "failed": 0 }
}
用/items2/240708检查一下商品数据
Id是商品的Id,而指标则是成为该商品推荐指标的其他商品。
实时查询
创建的最棒的部分就是实时查询
{ "query": { "bool": { "should": [ { "terms": {"indicators" : [240708], "boost": 2}} ] } }
}
发送请求到 127.0.0.1:9200/items2/_search,你会得到三个结果。商品312728, 商品305675和 商品346067。正是会与商品240708一起购买的三件商品。
太棒了!现在大量的资源需求已经不是问题了。那么,另外两个问题呢?
“冷启动”问题:我不认识你
创建推荐系统时,最常见的就是冷启动问题,因为系统中不会有新用户的任何行为记录。那么,系统应该向他们推荐什么呢?
请看我们最近构建的推荐系统。你觉得这个结果有什么异常吗?是的,结果只返回3个推荐项——只有3个。你打算如何向客户展示这三个可怜的推荐项呢?
为了更好的用户体验,让我们将未受推荐的商品放在列表末尾。
{ "query": { "bool": { "should": [ { "terms": {"indicators" : [240708]}}, { "constant_score": {"filter" : {"match_all": {}}, "boost" : 0.000001}} ] } }
}
你可以使用常数分数来返回所有其他项。
但是,你也需要对所有未受推荐的项目进行排序,这样即使没有再用户的行为中捕捉到,也有可能是用户会喜欢的商品。多数情况下,受欢迎的商品非常好用。如何确定一个商品是否受欢迎呢?
popular = np.zeros(items.shape[0]) def inc_popular(index): popular[index] += 1 trans2.apply(lambda row: inc_popular(row['items']), axis=1)
这很简单,逐个数商品的出现次数,出现次数最多的就最流行。让我们创建另一个索引items3。批量插入:
actions = []
for i in range(indicators.shape[0]): length = indicators[i].nonzero()[0].shape[0] real_indicators = items[indicators_indices[i, :length]].astype("int").tolist() id = items[i] action = { "index" : { "_index" : "items3", "_id" : str(id) } } # url = "http://127.0.0.1:9200/items/_create/" + str(id) data = { "id": int(id), "indicators": real_indicators, "popular": popular[i] } actions.append(json.dumps(action)) actions.append(json.dumps(data)) if len(actions) == 200: actions_string = "\n".join(actions) + "\n" actions = [] url = "http://127.0.0.1:9200/_bulk/" headers = { "Content-Type" : "application/x-ndjson" } requests.post(url, headers=headers, data=actions_string)if len(actions) > 0: actions_string = "\n".join(actions) + "\n" actions = []url = "http://127.0.0.1:9200/_bulk/" headers = { "Content-Type" : "application/x-ndjson" } requests.post(url, headers=headers, data=actions_string)
这个索引阶段中也包括流行字段。所以数据会是这样的:
{ "id": 240708, "indicators": [ 305675, 346067, 312728 ], "popular": 3.0
}
你将会有三个字段。ID,指标(与前面类似),以及流行字段(也就是用户购买的商品数量)。在前面的查询中加入popular。
函数得分:组合得分的方法
所以,现在有多个得分来源,即指标分数和流行分数,那么如何将分数组合起来呢?
可以用弹性搜索的功能评分。
{ "query": { "function_score":{ "query": { "bool": { "should": [ { "terms": {"indicators" : [240708], "boost": 2}}, { "constant_score": {"filter" : {"match_all": {}}, "boost" : 0.000001}} ] } }, "functions":[ { "filter": {"range": {"popular": {"gt": 0}}}, "script_score" : { "script" : { "source": "doc['popular'].value * 0.1" } } } ], "score_mode": "sum", "min_score" : 0 } }
}
修改查询,并添加一个功能评分,将流行值的0.1倍添加到上面的常量分数中。不必执着于0.1,也可以使用其他函数,甚至自然对数。像这样:
Math.log(doc['popular'].value)
现在,可以看到最受欢迎的商品461686排在第四位,仅低于推荐商品。
下面依次是其它受欢迎的商品。
不变的、静态的推荐
如你所见,每次实时查询时,推荐结果都保持不变。一方面这很好,因为我们的技术是可复制的;但另一方面,用户可能对此并不满意。Ted Dunnings在他的书中说,在推荐的第20个商品后,点击率将会非常低。这意味着在那之后我们推荐的任何商品都不会被用户知道。
怎么解决这个问题呢?
有一种技术叫做抖动。它会在查询时产生一种随机干扰,使最不受推荐的商品的排名提前,但同时又保证受到强烈推荐的商品仍然在推荐列表的前几位。
{ "query": { "function_score":{ "query": { "bool": { "should": [ { "terms": {"indicators" : [240708], "boost": 2}}, { "constant_score": {"filter" : {"match_all": {}}, "boost" : 0.000001}} ] } }, "functions":[ { "filter": {"range": {"popular": {"gt": 1}}}, "script_score" : { "script" : { "source": "0.1 * Math.log(doc['popular'].value)" } } }, { "filter": {"match_all": {}}, "random_score": {} } ], "score_mode": "sum", "min_score" : 0 } }
}
随机分数会给出使所有商品均匀分布的随机干扰。得分很小,这样最受欢迎的推荐商品排名就不会下降。好处在于用户将浏览时不必滚动到第二或第三页,只需要点击浏览器上的刷新按钮,就会得到新的内容。
◆
精彩推荐
◆

推荐阅读
王霸之路:从0.1到2.0,一文看尽TensorFlow“奋斗史”
伯克利人工智能研究院开源深度学习数据压缩方法Bit-Swap,性能创新高
NLP被英语统治?打破成见,英语不应是「自然语言」同义词
TensorFlow2.0正式版发布,极简安装TF2.0(CPU&GPU)教程
肖仰华:知识图谱构建的三要素、三原则和九大策略 | AI ProCon 2019
微软语音AI技术与微软听听文档小程序实践 | AI ProCon 2019
AI落地遭“卡脖子”困境:为什么说联邦学习是解决良方?
10分钟搭建你的第一个图像识别模型 | 附完整代码
限时早鸟票 | 2019 中国大数据技术大会(BDTC)超豪华盛宴抢先看!

你点的每个“在看”,我都认真当成了喜欢
相关文章:
CUDA Samples: Ray Tracking
以下CUDA sample是分别用C和CUDA实现的生成光线跟踪图像,并对其中使用到的CUDA函数进行了解说,code参考了《GPU高性能编程CUDA实战》一书的第六章,CUDA各实现包括了使用常量内存和不使用常量内存两种方法,各个文件内容如下&#x…

从产品的适用性以及费用方面考虑
物联宇手持终端在对比性价比高低应该从产品的适用性以及费用方面考虑。不过在选择时不一定要整机,可以按实际需求让厂商定做和行业需要功能的手持机,这样有针对性的定制更能体现整体的性价效率。转载于:https://blog.51cto.com/14222294/2386642

杨学海:跨境电商新通道-进口保税直邮模式解析
为什么80%的码农都做不了架构师?>>> 杨学海:跨境电商新通道-进口保税直邮模式解析 广州威云供应链管理公司总经理杨学海在第九届中国中小企业电子商务大会上表示,其品牌海外通要为跨境电子商务提供一个更加快速、便捷、低成本&am…
CUDA Samples: heat conduction(模拟热传导)
以下CUDA sample是分别用C和CUDA实现的模拟热传导生成的图像,并对其中使用到的CUDA函数进行了解说,code参考了《GPU高性能编程CUDA实战》一书的第七章,各个文件内容如下:funset.cpp:#include "funset.hpp" #include <…

2020应届生:今年秋招也太太太太太难了吧!
讲个简短的鬼故事:2020秋招已经过去一大半了!回顾9月,你可能以为秋招还有很多机会,还有大把时间准备。然而各大名企的实际进度却不等人。阿里巴巴9月12日网申截止;腾讯9月15日网申截止;宝洁9月20日关闭网申…

PDF文字怎么编辑,PDF文档编辑方法
有时候遇到PDF文件不是自己制作的或者是制作的有点匆忙,会有文字遗漏或者打错的时候,我们使用就会有点麻烦就需要把文件中的文字进行编辑修改,那么具体怎么做呢?小伙伴们都挺好奇吧,今天就来跟大家分享一下。操作软件&…

浏览器是怎样工作的:渲染引擎,HTML解析
2019独角兽企业重金招聘Python工程师标准>>> 渲染引擎 渲染引擎的职责是……渲染,也就是把请求的内容显示到浏览器屏幕上。 默认情况下渲染引擎可以显示HTML,XML文档以及图片。 通过插件(浏览器扩展)它可以显示其它类型…
CUDA Samples: Calculate Histogram(atomicAdd)
以下CUDA sample是分别用C和CUDA实现的计算一维直方图,并对其中使用到的CUDA函数进行了解说,code参考了《GPU高性能编程CUDA实战》一书的第九章,各个文件内容如下:funset.cpp:#include "funset.hpp" #include <rando…

glusterfs基本操作
基本操作 集群节点 扩展集群 1,必须做hosts域名解析其实通过IP地址也能做集群,但是不建议这种方式. 192.168.1.210 glusterfs04 2, 添加节点到集群中,在当前所有集群节点中都需要执行 gluster peer probe glusterfs04 3,查看对等状态 gluster peer status 查看集群节点信息 gl…

100多次竞赛后,他研发了一个几乎可以解决所有机器学习问题的框架
(图片由AI科技大本营付费下载自视觉中国)作者 | XI YANG来源 | 知乎(机器学习之路)一个叫 Abhishek Thakur 的数据科学家,在他的 Linkedin 发表了一篇文章 Approaching (Almost) Any Machine Learning Problem…

mysql中char与varchar的区别分析(补充一句,int和integer没区别)
转自:http://www.jb51.net/article/23575.htm 在mysql教程中char与varchar的区别呢,都是用来存储字符串的,只是他们的保存方式不一样罢了,char有固定的长度,而varchar属于可变长的字符类型。har与varchar的区别 &#…
CUDA Samples: Streams' usage
以下CUDA sample是分别用C和CUDA实现的流的使用code,并对其中使用到的CUDA函数进行了解说,code参考了《GPU高性能编程CUDA实战》一书的第十章,各个文件内容如下:funset.cpp:#include "funset.hpp" #include <random&…

你的神经网络不起作用的37个理由
(图片由AI科技大本营付费下载自视觉中国)作者 | Slav Ivanov译者 | 吴金笛校对 | 丁楠雅、林亦霖编辑 | 王菁来源 | 数据派THU(ID:DatapiTHU)【导语】本文列举了在搭建神经网络过程中的37个易错点,并给出了…

菜鸟Vue学习笔记(三)
菜鸟Vue学习笔记(三)本周使用了Vue来操作表单,接下来说下Vue中双向绑定表单元素的用法。Vue中双向绑定是使用的v-model,所谓的双向绑定即改变变量的值,表单元素的值也会改变,同样的,改变表单元素…

Python中的注释(转)
一、单行注释单行注释以#开头,例如:print 6 #输出6二、多行注释(Python的注释只有针对于单行的注释(用#),这是一种变通的方法)多行注释用三引号将注释括起来,例如:多行注释多行注释三…
CUDA Samples: dot product(使用零拷贝内存)
以下CUDA sample是分别用C和CUDA实现的点积运算code,CUDA包括普通实现和采用零拷贝内存实现两种,并对其中使用到的CUDA函数进行了解说,code参考了《GPU高性能编程CUDA实战》一书的第十一章,各个文件内容如下:funset.cp…

一文读懂线性回归、岭回归和Lasso回归
(图片由AI科技大本营付费下载自视觉中国)作者 | 文杰编辑 | yuquanle本文介绍线性回归模型,从梯度下降和最小二乘的角度来求解线性回归问题,以概率的方式解释了线性回归为什么采用平方损失,然后介绍了线性回归中常用的…

tf.matmul / tf.multiply
import tensorflow as tfimport numpy as np 1.tf.placeholder placeholder()函数是在神经网络构建graph的时候在模型中的占位,此时并没有把要输入的数据传入模型,它只会分配必要的内存。 等建立session,在会话中,运行模型的时候通…

Java 匿名类也能使用构造函数
为什么80%的码农都做不了架构师?>>> 匿名类虽然没有名字,但可以有一个初始化块来充当构造函数。 public enum Ops {ADD, SUB} public class Calculator { private int i, j, result; public Calculator() {} public Calculator(int _i, …
CUDA Samples: matrix multiplication(C = A * B)
以下CUDA sample是分别用C和CUDA实现的两矩阵相乘运算code即C A*B,CUDA中包含了两种核函数的实现方法,第一种方法来自于CUDA Samples\v8.0\0_Simple\matrixMul,第二种采用普通的方法实现,第一种方法较快,但有些复杂&am…

业界首个实时多目标跟踪系统开源
(图片由AI科技大本营付费下载自视觉中国)作者 | CV君来源 | 我爱计算机视觉(ID:aicvml)相对业界研究比较多的单目标跟踪,多目标跟踪(Multi-Object Tracking,MOT)系统在实…

python基础 练习题
【练习题1】实现一个整数加法计算器如 content input(">>> ") # 59 , 64 count0 while 1:contentinput(>>>)s1 content.split()print(s1)count 0for i in s1:count int(i)print(count) 【练习题2】请编写1 - 100 所有数的和 sum0 for i in r…

[再寄小读者之数学篇](2014-04-18 from 352558840@qq.com [南开大学 2014 年高等代数考研试题]二次型的零点)...
(2014-04-18 from 352558840qq.com [南开大学 2014 年高等代数考研试题]) 设 ${\bf A}$ 为实对称矩阵, 存在线性无关的向量 ${\bf x}_1,{\bf x}_2$, 使得 ${\bf x}_1^T{\bf A}{\bf x}_1>0$, ${\bf x}_2^T{\bf A}{\bf x}_2<0$. 证明: 存在线性无关的向量 ${\bf x}_3,{\bf …

从0到1详解推荐系统中的嵌入方法,原理、算法到应用都讲明白了
(图片由AI科技大本营付费下载自视觉中国)作者丨gongyouliu编辑丨lily来源 | 大数据与人工智能(ID:)前言作者曾在这篇文章中提到,矩阵分解算法是一类嵌入方法,通过将用户行为矩阵分解为用户特征矩…

iOS-Swift中的递增(++)和递减(--)被取消的原因-官方答复
众所周知,在很多编程语言中,对一个变量递增1用,递减1用--,在Swift3之前也是可以这么用的,但之后被取消了。 所以在目前Swift5的版本中,只能用1和-1来进行递增和递减了 如果坚持用或--将会提示以下错误&…
CUDA Samples: 获取设备属性信息
通过调用CUDA的cudaGetDeviceProperties函数可以获得指定设备的相关信息,此函数会根据GPU显卡和CUDA版本的不同得到的结果也有所差异,下面code列出了经常用到的设备信息:#include "funset.hpp" #include <iostream> #include…

apache代理模块proxy使用
1、安装proxy模块[rootlocalhost modules]# cd /usr/local/src/httpd-2.2.16 [rootlocalhost httpd-2.2.16]# cd modules [rootlocalhost modules]# ls aaa config5.m4 debug filters ldap Makefile.in NWGNUmakefile ssl arch database echo …
CUDA Samples: image normalize(mean/standard deviation)
以下CUDA sample是分别用C和CUDA实现的通过均值和标准差对图像进行类似归一化的操作,并对其中使用到的CUDA函数进行了解说,各个文件内容如下:关于均值和标准差的计算公式可参考: http://blog.csdn.net/fengbingchun/article/detai…

中文预训练ALBERT模型来了:小模型登顶GLUE,Base版模型小10倍、速度快1倍
(图片由AI科技大本营付费下载自视觉中国)作者 | 徐亮(实在智能算法专家) 来源 | AINLP(ID:nlpjob)谷歌ALBERT论文刚刚出炉一周,中文预训练ALBERT模型来了,感兴趣的同学可以直接尝鲜试…

树莓派安装go
简介 大学的时候在使用openfalcon的时候讲过这个东西,但是那时候是介绍open-falcon的,所以感觉不是很具体,所以今天在安装frp的时候也碰到了这个问题,我就具体的说下 安装go1.4 编译最新版本的go的时候一定要先编译安装go1.4&…