<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Algorithm &#8211; 编码无悔 /  Intent &amp; Focused</title>
	<atom:link href="https://www.codelast.com/category/algorithm/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.codelast.com</link>
	<description>最优化之路</description>
	<lastBuildDate>Mon, 16 Sep 2024 05:44:52 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>[原创] 如何判断已经启动的TF-Serving服务是否正在使用</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%b7%b2%e7%bb%8f%e5%90%af%e5%8a%a8%e7%9a%84tf-serving%e6%9c%8d%e5%8a%a1%e6%98%af%e5%90%a6%e6%ad%a3%e5%9c%a8%e4%bd%bf%e7%94%a8/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%b7%b2%e7%bb%8f%e5%90%af%e5%8a%a8%e7%9a%84tf-serving%e6%9c%8d%e5%8a%a1%e6%98%af%e5%90%a6%e6%ad%a3%e5%9c%a8%e4%bd%bf%e7%94%a8/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Mon, 16 Sep 2024 04:27:03 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[TF-Serving]]></category>
		<category><![CDATA[TFServing]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=14136</guid>

					<description><![CDATA[<p>在一台服务器上，如果启动了一个TF-Serving服务，我们知道它占了资源，却不知道它是在空跑还是<span style="color:#ff0000;">真的在用</span>。<br />
本文描述了怎样判断它是否真的在用。<br />
<span id="more-14136"></span></p>
<div>
	用 nvidia-smi 命令能看到 TF-Serving 服务在运行：</div>
<p><img decoding="async" alt="TF-Serving is running" src="https://www.codelast.com/wp-content/uploads/2024/09/tf_serving_running.png" style="width: 700px; height: 149px;" /></p>
<div>
<div>
		其进程id是 22871，于是进一步查询这个进程的信息：</div>
<blockquote>
<div>
			ps -ef &#124; grep 22871</div>
</blockquote>
<div>
		输出类似于：</div>
<blockquote>
<div>
			root&#160; &#160; &#160;22871 22729 83 13:42 pts/0&#160; &#160; 00:06:35 tensorflow_model_server --port=8500 --rest_api_port=8501 --model_name=codelast --model_base_path=/models/codelast</div>
</blockquote>
<div>
		可见其REST服务的端口号为 8501。<br />
		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a>
<div>
			于是我们可以用 tcpdump 来捕获并分析流量，运行以下命令(需要 root 权限)：：</div>
<blockquote>
<div>
				sudo tcpdump -vv -i any &#39;port 8501&#39;</div>
</blockquote>
<div>
			如果有客户端正在向这个TF-Serving服务发送请求，我们应会看到这个命令有输出，不断在刷屏，类似于：
<div>
				<span style="color:#0000ff;">14:27:59.174425 IP (tos 0x0, ttl 60, id 51707, offset 0, flags [DF], proto TCP (6), length 1500)</span></div>
<div>
				<span style="color:#0000ff;">node.codelast.com.60679</span></div></div></div></div>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%b7%b2%e7%bb%8f%e5%90%af%e5%8a%a8%e7%9a%84tf-serving%e6%9c%8d%e5%8a%a1%e6%98%af%e5%90%a6%e6%ad%a3%e5%9c%a8%e4%bd%bf%e7%94%a8/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>在一台服务器上，如果启动了一个TF-Serving服务，我们知道它占了资源，却不知道它是在空跑还是<span style="color:#ff0000;">真的在用</span>。<br />
本文描述了怎样判断它是否真的在用。<br />
<span id="more-14136"></span></p>
<div>
	用 nvidia-smi 命令能看到 TF-Serving 服务在运行：</div>
<p><img decoding="async" alt="TF-Serving is running" src="https://www.codelast.com/wp-content/uploads/2024/09/tf_serving_running.png" style="width: 700px; height: 149px;" /></p>
<div>
<div>
		其进程id是 22871，于是进一步查询这个进程的信息：</div>
<blockquote>
<div>
			ps -ef | grep 22871</div>
</blockquote>
<div>
		输出类似于：</div>
<blockquote>
<div>
			root&nbsp; &nbsp; &nbsp;22871 22729 83 13:42 pts/0&nbsp; &nbsp; 00:06:35 tensorflow_model_server --port=8500 --rest_api_port=8501 --model_name=codelast --model_base_path=/models/codelast</div>
</blockquote>
<div>
		可见其REST服务的端口号为 8501。<br />
		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<div>
			于是我们可以用 tcpdump 来捕获并分析流量，运行以下命令(需要 root 权限)：：</div>
<blockquote>
<div>
				sudo tcpdump -vv -i any &#39;port 8501&#39;</div>
</blockquote>
<div>
			如果有客户端正在向这个TF-Serving服务发送请求，我们应会看到这个命令有输出，不断在刷屏，类似于：</p>
<div>
				<span style="color:#0000ff;">14:27:59.174425 IP (tos 0x0, ttl 60, id 51707, offset 0, flags [DF], proto TCP (6), length 1500)</span></div>
<div>
				<span style="color:#0000ff;">node.codelast.com.60679 &gt; 172.17.0.2.cmtp-mgt: Flags [.], cksum 0x310f (correct), seq 617580:619040, ack 1, win 63, length 1460</span></div>
<div>
				<span style="color:#0000ff;">14:27:59.174453 IP (tos 0x0, ttl 60, id 39347, offset 0, flags [DF], proto TCP (6), length 1500)</span></div>
<div>
				<span style="color:#0000ff;">node.codelast.com.32739 &gt; 172.17.0.2.cmtp-mgt: Flags [.], cksum 0x9354 (correct), seq 44268904:44270364, ack 1, win 86, length 1460</span></div>
<p>			如果没有请求发到TF-Serving服务，那么上面的命令什么都不会输出，就表明TF-Serving服务没在用。<br />
			<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
			<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
			转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
			感谢关注我的微信公众号（微信扫一扫）：<br />
			<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
			以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
				<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
</p></div>
<p>
		&nbsp;</div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%a6%82%e4%bd%95%e5%88%a4%e6%96%ad%e5%b7%b2%e7%bb%8f%e5%90%af%e5%8a%a8%e7%9a%84tf-serving%e6%9c%8d%e5%8a%a1%e6%98%af%e5%90%a6%e6%ad%a3%e5%9c%a8%e4%bd%bf%e7%94%a8/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创]《使用 fastText 做中文文本分类》文章合集</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b%e3%80%8a%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb%e3%80%8b%e6%96%87%e7%ab%a0%e5%90%88%e9%9b%86/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b%e3%80%8a%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb%e3%80%8b%e6%96%87%e7%ab%a0%e5%90%88%e9%9b%86/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 29 Jul 2020 10:46:59 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[fastText]]></category>
		<category><![CDATA[中文]]></category>
		<category><![CDATA[文本分类]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=12856</guid>

					<description><![CDATA[<p>本文描述了如何使用 <a href="https://fasttext.cc/" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">fastText</span></a> 对中文进行文本分类的过程，只有实操，基本没有理论。<br />
以下按顺序编排。</p>
<p><span style="background-color: rgb(255, 255, 0);">✓</span>&#160;<a href="https://www.codelast.com/?p=12754" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(1)</a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;<a href="https://www.codelast.com/?p=12777" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(2)</a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;<a href="https://www.codelast.com/?p=12796" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(3)</a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;<a href="https://www.codelast.com/?p=12827" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(4)</a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;<a href="https://www.codelast.com/?p=12840" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(5)</a>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b%e3%80%8a%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb%e3%80%8b%e6%96%87%e7%ab%a0%e5%90%88%e9%9b%86/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p>本文描述了如何使用 <a href="https://fasttext.cc/" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">fastText</span></a> 对中文进行文本分类的过程，只有实操，基本没有理论。<br />
以下按顺序编排。</p>
<p><span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;<a href="https://www.codelast.com/?p=12754" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(1)</a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;<a href="https://www.codelast.com/?p=12777" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(2)</a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;<a href="https://www.codelast.com/?p=12796" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(3)</a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;<a href="https://www.codelast.com/?p=12827" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(4)</a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;<a href="https://www.codelast.com/?p=12840" rel="noopener noreferrer" target="_blank">使用 fastText 做中文文本分类(5)</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b%e3%80%8a%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb%e3%80%8b%e6%96%87%e7%ab%a0%e5%90%88%e9%9b%86/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 使用 fastText 做中文文本分类(5)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb5/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb5/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 29 Jul 2020 09:48:07 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[fastText]]></category>
		<category><![CDATA[FastText4j]]></category>
		<category><![CDATA[中文]]></category>
		<category><![CDATA[文本分类]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=12840</guid>

					<description><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p>前面说的模型训练、预测过程，是用 fastText 可执行程序完成的。fastText提供了Python的接口，同样的功能也可以用Python实现。如果数据量比较小，单机做文本分类没啥问题。但我的数据量比较大，几十G的文本数据，单机加载模型、预测分类太耗资源了，而且速度慢。<br />
并行这种事嘛，交给Map-Reduce job来做是最合适不过了，不过，要在Hadoop集群上安装fastText的Python包是不可能的，所以我只能找一下，fastText的模型怎么用Java加载，从而在M-R job中并行地去做预测。<br />
<span id="more-12840"></span><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;选择<br />
网上能搜到好些个 fastText 的&#8220;Java版&#8221;，比如 <a href="https://github.com/vinhkhuc/JFastText" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">JFastText</span></a>，它是 fastText 的一个Java wrapper；又比如&#160;<a href="https://github.com/mayabot/mynlp/tree/master/fastText4j" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">FastText4j</span></a>，它是一个完全由 Kotlin &#38; Java 实现的 fastText 实现。还有其他的，没有调研。<br />
看了 FastText4j 的自我介绍：</p>
<blockquote>
<div>
		● 100%由Kotlin &#38; Java实现</div>
<div>
		● 良好的API</div>
<div>
		● 兼容官方原版的预训练模型</div>
<div>
		● 提供所有的包括train、test等api</div>
<div>
		● 支持自有模型存储格式，可以使用MMAP快速加载大模型</div>
</blockquote>
<div>
	我心动了，马上试用。
<p>	<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;Maven项目引入 FastText4j 依赖</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:12.0pt;">
<span style="color:#e8bf6a;">&#60;dependency&#62;
</span><span style="color:#e8bf6a;">  &#60;groupId&#62;</span>com.mayabot.mynlp</pre></div>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb5/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p>前面说的模型训练、预测过程，是用 fastText 可执行程序完成的。fastText提供了Python的接口，同样的功能也可以用Python实现。如果数据量比较小，单机做文本分类没啥问题。但我的数据量比较大，几十G的文本数据，单机加载模型、预测分类太耗资源了，而且速度慢。<br />
并行这种事嘛，交给Map-Reduce job来做是最合适不过了，不过，要在Hadoop集群上安装fastText的Python包是不可能的，所以我只能找一下，fastText的模型怎么用Java加载，从而在M-R job中并行地去做预测。<br />
<span id="more-12840"></span><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;选择<br />
网上能搜到好些个 fastText 的&ldquo;Java版&rdquo;，比如 <a href="https://github.com/vinhkhuc/JFastText" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">JFastText</span></a>，它是 fastText 的一个Java wrapper；又比如&nbsp;<a href="https://github.com/mayabot/mynlp/tree/master/fastText4j" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">FastText4j</span></a>，它是一个完全由 Kotlin &amp; Java 实现的 fastText 实现。还有其他的，没有调研。<br />
看了 FastText4j 的自我介绍：</p>
<blockquote>
<div>
		● 100%由Kotlin &amp; Java实现</div>
<div>
		● 良好的API</div>
<div>
		● 兼容官方原版的预训练模型</div>
<div>
		● 提供所有的包括train、test等api</div>
<div>
		● 支持自有模型存储格式，可以使用MMAP快速加载大模型</div>
</blockquote>
<div>
	我心动了，马上试用。</p>
<p>	<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;Maven项目引入 FastText4j 依赖</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:12.0pt;">
<span style="color:#e8bf6a;">&lt;dependency&gt;
</span><span style="color:#e8bf6a;">  &lt;groupId&gt;</span>com.mayabot.mynlp<span style="color:#e8bf6a;">&lt;/groupId&gt;
</span><span style="color:#e8bf6a;">  &lt;artifactId&gt;</span>fastText4j<span style="color:#e8bf6a;">&lt;/artifactId&gt;
</span><span style="color:#e8bf6a;">  &lt;version&gt;</span>3.1.7<span style="color:#e8bf6a;">&lt;/version&gt;
</span><span style="color:#e8bf6a;">&lt;/dependency&gt;</span></pre>
<p>	这样就能在代码里用了。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;训练模型</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:12.0pt;">
<span style="color:#808080;">// </span><span style="color:#808080;font-family:'DejaVu Sans Mono',monospace;">用</span><span style="color:#808080;">FastText4j</span><span style="color:#808080;font-family:'DejaVu Sans Mono',monospace;">训练一个文本分类模型，模型保存成单个文件
</span>File trainFile = <span style="color:#cc7832;">new </span>File(<span style="color:#6a8759;">&quot;/home/codelast/labeled-data_train&quot;</span>)<span style="color:#cc7832;">;
</span>InputArgs inputArgs = <span style="color:#cc7832;">new </span>InputArgs()<span style="color:#cc7832;">;
</span>inputArgs.setLoss(LossName.<span style="color:#9876aa;font-style:italic;">softmax</span>)<span style="color:#cc7832;">;
</span>inputArgs.setLr(<span style="color:#6897bb;">1.0</span>)<span style="color:#cc7832;">;
</span>inputArgs.setEpoch(<span style="color:#6897bb;">25</span>)<span style="color:#cc7832;">;
</span>inputArgs.setWordNgrams(<span style="color:#6897bb;">2</span>)<span style="color:#cc7832;">;
</span>
FastText model = FastText.<span style="font-style:italic;">trainSupervised</span>(trainFile<span style="color:#cc7832;">, </span>inputArgs)<span style="color:#cc7832;">;
</span>model.saveModelToSingleFile(<span style="color:#cc7832;">new </span>File(<span style="color:#6a8759;">&quot;/home/codelast/model&quot;</span>))<span style="color:#cc7832;">;</span></pre>
<p>	训练的参数，包括 lr，epoch，wordNgrams 的含义，都和 fastText 的原版一致。和 fastText 默认生成 .bin &amp; .vec 两个模型文件不同，FastText4j 可以用 saveModelToSingleFile() 方法来生成一个单一的模型文件，如果用 saveModel() 方法的话，则会在一个目录下生成4个文件（如果是这种形式的话，加载模型的时候，4个文件缺一不可）：</p>
<blockquote>
<div>
			args.bin</div>
<div>
			dict.bin</div>
<div>
			input.matrix</div>
<div>
			output.matrix</div>
</blockquote>
<div>
		如果要在Java Map-Reduce job中加载模型，把模型放到 distributed cache 中分发，当然是一个文件最方便。所以强烈建议把模型save成单一文件。<br />
		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
		<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;加载模型并测试效果</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:12.0pt;">
<span style="color:#808080;">// </span><span style="color:#808080;font-family:'DejaVu Sans Mono',monospace;">加载模型
</span>FastText model = FastText.<span style="color:#9876aa;font-style:italic;">Companion</span>.loadModelFromSingleFile(<span style="color:#cc7832;">new </span>File(<span style="color:#6a8759;">&quot;/home/codelast/model&quot;</span>))<span style="color:#cc7832;">;
</span>System.<span style="color:#9876aa;font-style:italic;">out</span>.println(<span style="color:#6a8759;">&quot;load model done, will do test...&quot;</span>)<span style="color:#cc7832;">;
</span><span style="color:#808080;">// </span><span style="color:#808080;font-family:'DejaVu Sans Mono',monospace;">测试模型效果
</span>model.test(<span style="color:#cc7832;">new </span>File(<span style="color:#6a8759;">&quot;/home/codelast/labeled-data_valid&quot;</span>)<span style="color:#cc7832;">, </span><span style="color:#6897bb;">1</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">0</span><span style="color:#cc7832;">, true</span>)<span style="color:#cc7832;">;</span></pre>
<p>		输出：</p>
<blockquote>
<div>
				load model done, will do test...</div>
<div>
				F1-Score : 0.953652 Precision : 0.949348 Recall : 0.957996&nbsp; __label__娱乐</div>
<div>
				F1-Score : 0.704064 Precision : 0.702055 Recall : 0.706085&nbsp; __label__社会</div>
<div>
				F1-Score : 0.929426 Precision : 0.917355 Recall : 0.941818&nbsp; __label__历史</div>
<div>
				F1-Score : 0.784775 Precision : 0.784232 Recall : 0.785319&nbsp; __label__时政</div>
<div>
				F1-Score : 0.969314 Precision : 0.967568 Recall : 0.971067&nbsp; __label__汽车</div>
<div>
				F1-Score : 0.910314 Precision : 0.914414 Recall : 0.906250&nbsp; __label__时尚</div>
<div>
				F1-Score : 0.899281 Precision : 0.903614 Recall : 0.894988&nbsp; __label__健康</div>
<div>
				F1-Score : 0.929919 Precision : 0.905512 Recall : 0.955679&nbsp; __label__美食</div>
<div>
				F1-Score : 0.908136 Precision : 0.894057 Recall : 0.922667&nbsp; __label__军事</div>
<div>
				F1-Score : 0.967391 Precision : 0.975342 Recall : 0.959569&nbsp; __label__体育</div>
<div>
				F1-Score : 0.907618 Precision : 0.915033 Recall : 0.900322&nbsp; __label__育儿</div>
<div>
				F1-Score : 0.782895 Precision : 0.760383 Recall : 0.806780&nbsp; __label__情感</div>
<div>
				F1-Score : 0.863946 Precision : 0.866894 Recall : 0.861017&nbsp; __label__财经</div>
<div>
				F1-Score : 0.905188 Precision : 0.920000 Recall : 0.890845&nbsp; __label__教育</div>
<div>
				F1-Score : 0.781431 Precision : 0.792157 Recall : 0.770992&nbsp; __label__文化</div>
<div>
				F1-Score : 0.892495 Precision : 0.894309 Recall : 0.890688&nbsp; __label__游戏</div>
<div>
				F1-Score : 0.830882 Precision : 0.801418 Recall : 0.862595&nbsp; __label__科技</div>
<div>
				F1-Score : 0.795455 Precision : 0.781250 Recall : 0.810185&nbsp; __label__旅游</div>
<div>
				F1-Score : 0.843537 Precision : 0.826667 Recall : 0.861111&nbsp; __label__动漫</div>
<div>
				F1-Score : 0.960961 Precision : 0.969697 Recall : 0.952381&nbsp; __label__占卜</div>
<div>
				F1-Score : 0.915361 Precision : 0.912500 Recall : 0.918239&nbsp; __label__数码</div>
<div>
				F1-Score : 0.553191 Precision : 0.601852 Recall : 0.511811&nbsp; __label__搞笑</div>
<div>
				F1-Score : 0.788104 Precision : 0.834646 Recall : 0.746479&nbsp; __label__农林牧副渔</div>
<div>
				F1-Score : 0.797048 Precision : 0.830769 Recall : 0.765957&nbsp; __label__科学</div>
<div>
				F1-Score : 0.788462 Precision : 0.828283 Recall : 0.752294&nbsp; __label__家居</div>
<div>
				F1-Score : 0.831579 Precision : 0.877778 Recall : 0.790000&nbsp; __label__房产</div>
<div>
				F1-Score : 0.674286 Precision : 0.710843 Recall : 0.641304&nbsp; __label__生活方式</div>
<div>
				F1-Score : 0.908108 Precision : 0.933333 Recall : 0.884211&nbsp; __label__宠物</div>
<div>
				F1-Score : 0.546667 Precision : 0.546667 Recall : 0.546667&nbsp; __label__宗教</div>
<div>
				F1-Score : 0.706767 Precision : 0.671429 Recall : 0.746032&nbsp; __label__职场</div>
<div>
				F1-Score : 0.951220 Precision : 0.928571 Recall : 0.975000&nbsp; __label__天气</div>
<div>
				F1-Score : 0.666667 Precision : 0.909091 Recall : 0.526316&nbsp; __label__摄影</div>
<div>
				F1-Score : 0.707692 Precision : 0.718750 Recall : 0.696970&nbsp; __label__法律</div>
<div>
				F1-Score : 0.750000 Precision : 1.000000 Recall : 0.600000&nbsp; __label__彩票</div>
<div>
				F1-Score : 0.333333 Precision : 1.000000 Recall : 0.200000&nbsp; __label__移民</div>
<div>
				F1-Score : 0.000000 Precision : -------- Recall : 0.000000&nbsp; __label__生活百科</div>
<div>
				N<span style="white-space:pre"> </span>10703</div>
<div>
				P@1<span style="white-space:pre"> </span>0.870</div>
<div>
				R@1<span style="white-space:pre"> </span>0.870</div>
</blockquote>
<p>		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
		<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;预测一段文本的label</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:12.0pt;">
<span style="color:#808080;">// </span><span style="color:#808080;font-family:'DejaVu Sans Mono',monospace;">预测一个分好词的</span><span style="color:#808080;">string</span><span style="color:#808080;font-family:'DejaVu Sans Mono',monospace;">的</span><span style="color:#808080;">label
</span>List&lt;ScoreLabelPair&gt; result = model.predict(Arrays.<span style="font-style:italic;">asList</span>(<span style="color:#6a8759;">&quot;</span><span style="color:#6a8759;font-family:'DejaVu Sans Mono',monospace;">人民网 辽宁 频道 人民网 沈阳 月</span><span style="color:#6a8759;"> 10 </span><span style="color:#6a8759;font-family:'DejaVu Sans Mono',monospace;">日电 日前 进一步 增强 全民 节能 意识</span><span style="color:#6a8759;">&quot;</span>.split(<span style="color:#6a8759;">&quot; &quot;</span>))<span style="color:#cc7832;">, </span><span style="color:#6897bb;">1</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">0</span>)<span style="color:#cc7832;">;
</span>System.<span style="color:#9876aa;font-style:italic;">out</span>.println(result.get(<span style="color:#6897bb;">0</span>).getLabel())<span style="color:#cc7832;">;</span></pre>
<p>		输出：</p>
<blockquote>
<p>
				__label__社会</p>
</blockquote>
<p>		注意这里的文本应该是分好词的、空格分隔的、清洗过的文本。<br />
		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
		<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;压缩模型<br />
		如果一个模型文件体积太大，可能放不进 distributed cache 中，所以压缩模型体积这个功能很有用。以我的模型为例，接近900MB的大小，压缩之后会变成 100 多MB，模型的Precision &amp; Recall指标却没有变差多少，值。</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:12.0pt;">
<span style="color:#808080;">// </span><span style="color:#808080;font-family:'DejaVu Sans Mono',monospace;">压缩模型并保存。加载压缩过的模型可以节省内存
</span>FastText qmodel = model.quantize(<span style="color:#6897bb;">2</span><span style="color:#cc7832;">, false, false</span>)<span style="color:#cc7832;">;
</span>qmodel.saveModelToSingleFile(<span style="color:#cc7832;">new </span>File(<span style="color:#6a8759;">&quot;/home/codelast/model_compressed&quot;</span>))<span style="color:#cc7832;">;</span></pre>
<p>		保存成压缩过的模型是一次性的操作，以后再加载模型的话，就加载这个压缩过的模型了。</p>
<p>		<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;后记<br />
		通过 FastText4j 在&nbsp;Map-Reduce job 中并行做文本分类，成功地让文本分类任务提高了无数倍的速度，达到了实用的水平。</div>
</div>
<p>
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb5/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 使用 fastText 做中文文本分类(4)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb4/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb4/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 29 Jul 2020 09:47:42 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[fastText]]></category>
		<category><![CDATA[中文]]></category>
		<category><![CDATA[文本分类]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=12827</guid>

					<description><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><span style="background-color: rgb(255, 255, 0);">✓</span>&#160;开始训练第一个文本分类模型<br />
标注好的数据，其格式为：</p>
<blockquote>
<p>
		__label__科技 月 10 日 网通 社从 高合 汽车 获悉 华人 运通 微软 2020 世界 人工智能 大会 云端 峰会 WAIC 2020 上 达成 战略 合作 依托 微软 小冰 人工智能 技术 高合 汽车 上 落地 全球 首个 主动式 人工智能 伙伴 HiPhiGo 用户 提供 更好 交通 出行 体验 人工智能 交通 行业 创新 融合 发展 探讨 成立 联合 智能 计算 实验室 智能 汽车 载体 智捷 交通 多个 领域 展开 深度 合作 人工智能 前瞻 技术 研发 推动 智慧 出行 社会 持续 发展 微软 亚洲 互联网 工程院 院长 王永东 微软 华人 运通 合作 使 人工智能 技术 切实可行 落地 场景 得以 转化 真实有效 生产力 发挥 更大 价值 微软 华人 运通 携手 推进 人工智能 新兴 科技 汽车 智慧 智慧 出行 领域 广泛应用 产业 升级 社会 持续 发展 注入 新 活力 华人 运通 董事长 丁磊 此次 合作 顶级 人工智能 企业 智能 汽车 公司 强强 联手 AI 多项 领先 技术 全球 汽车行业 首次 量产 落地 世界 内 技术 领先 性 首款 智能 汽车 高合 HiPhi 有条不紊 推进 全球 首条 车路 协同 自动 驾驶 智能化 城市道路 示范 项目 盐城 开通 试运行 再 全球 首个 车路 城 一体化 5G 无人驾驶 交通 运营 样板 上海 张江 未来 公园 成功 落地 华人 运通 以人为本 人性化 需求 出发 人性化 智慧 打造 智能 汽车 智捷 交通 智慧 城市 三智 战略 各项 业务 稳步 推进 高合 首款 量产 车 HiPhi 2020 年底 小批量 试生产 2021 年 上市 交付</p>
</blockquote>
<p>按 fastText 的<a href="https://fasttext.cc/docs/en/supervised-tutorial.html" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">指南</span></a>，把这份数据按大概 9:1 的比例，分成training集和validation集，然后开始训练模型：</p>
<blockquote>
<p>
		./fasttext</p></blockquote>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb4/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;开始训练第一个文本分类模型<br />
标注好的数据，其格式为：</p>
<blockquote>
<p>
		__label__科技 月 10 日 网通 社从 高合 汽车 获悉 华人 运通 微软 2020 世界 人工智能 大会 云端 峰会 WAIC 2020 上 达成 战略 合作 依托 微软 小冰 人工智能 技术 高合 汽车 上 落地 全球 首个 主动式 人工智能 伙伴 HiPhiGo 用户 提供 更好 交通 出行 体验 人工智能 交通 行业 创新 融合 发展 探讨 成立 联合 智能 计算 实验室 智能 汽车 载体 智捷 交通 多个 领域 展开 深度 合作 人工智能 前瞻 技术 研发 推动 智慧 出行 社会 持续 发展 微软 亚洲 互联网 工程院 院长 王永东 微软 华人 运通 合作 使 人工智能 技术 切实可行 落地 场景 得以 转化 真实有效 生产力 发挥 更大 价值 微软 华人 运通 携手 推进 人工智能 新兴 科技 汽车 智慧 智慧 出行 领域 广泛应用 产业 升级 社会 持续 发展 注入 新 活力 华人 运通 董事长 丁磊 此次 合作 顶级 人工智能 企业 智能 汽车 公司 强强 联手 AI 多项 领先 技术 全球 汽车行业 首次 量产 落地 世界 内 技术 领先 性 首款 智能 汽车 高合 HiPhi 有条不紊 推进 全球 首条 车路 协同 自动 驾驶 智能化 城市道路 示范 项目 盐城 开通 试运行 再 全球 首个 车路 城 一体化 5G 无人驾驶 交通 运营 样板 上海 张江 未来 公园 成功 落地 华人 运通 以人为本 人性化 需求 出发 人性化 智慧 打造 智能 汽车 智捷 交通 智慧 城市 三智 战略 各项 业务 稳步 推进 高合 首款 量产 车 HiPhi 2020 年底 小批量 试生产 2021 年 上市 交付</p>
</blockquote>
<p>按 fastText 的<a href="https://fasttext.cc/docs/en/supervised-tutorial.html" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">指南</span></a>，把这份数据按大概 9:1 的比例，分成training集和validation集，然后开始训练模型：</p>
<blockquote>
<p>
		./fasttext supervised -input labeled-data_train -output model</p>
</blockquote>
<p>其中，labeled-data_train 是training集文件，model 是输出模型的文件名前缀。<br />
经过一段时间的等待（速度很快），当前目录下就生成了模型文件：<span style="color:#0000ff;">model.bin</span> 和 <span style="color:#0000ff;">model.vec</span>。<br />
<span id="more-12827"></span><br />
现在可以用validation集来检验一下模型效果了：</p>
<blockquote>
<p>
		./fasttext test model.bin labeled-data_valid 1</p>
</blockquote>
<p>其中，labeled-data_valid 是validation集文件，1表示只预测top 1的label。<br />
输出：</p>
<blockquote>
<div>
		N<span style="white-space:pre"> </span>10705</div>
<div>
		P@1<span style="white-space:pre"> </span>0.842</div>
<div>
		R@1<span style="white-space:pre"> </span>0.842</div>
</blockquote>
<div>
	即 <span style="color:#0000ff;">Precision</span>为0.842，<span style="color:#0000ff;">Recall</span>为0.842。这个结果还可以，但还能优化。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;模型调优<br />
	设置更详细的参数重新训练模型：</div>
<blockquote>
<div>
		./fasttext supervised -input labeled-data_train -output model -lr 1.0 -epoch 25 -wordNgrams 2</div>
</blockquote>
<div>
	其中：<br />
	-lr 1.0 表示 learning rate 设置成 1.0（通常值：0.1 ～ 1.0）。<br />
	-epoch 25 表示迭代的轮数设置成 25。<br />
	-wordNgrams 2 表示n-gram的值，一般使用2，表示2-gram。<br />
	这样训练出来的模型，再做一次test，结果变好了一些：</p>
<blockquote>
<div>
			N<span style="white-space:pre"> </span>10705</div>
<div>
			P@1<span style="white-space:pre"> </span>0.878</div>
<div>
			R@1<span style="white-space:pre"> </span>0.878</div>
</blockquote>
<div>
		这里只对模型优化做了简单的尝试。</p>
<p>		<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;交互模式下预测文本的分类<br />
		执行以下命令：</p>
<blockquote>
<p>
				./fasttext predict model.bin -</p>
</blockquote>
<p>		fastText会加载 model.bin 模型，进入交互模式，等待用户输入。<br />
		此时输入的应该是分好词之后的文本，例如&ldquo;网通 社从 高合 汽车 获悉 华人 运通 微软 2020 世界 人工智能 大会 云端 峰会 WAIC 2020 上 达成 战略 合作&rdquo;。一回车，fastText马上会返回该段文本的预测分类：</p>
<blockquote>
<p>
				__label__科技</p>
</blockquote>
<p>		这是个比较方便的调试方法。</p>
<p>		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
		<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
		转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
		感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
			<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
</p></div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 使用 fastText 做中文文本分类(3)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb3/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb3/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 29 Jul 2020 09:47:20 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[fastText]]></category>
		<category><![CDATA[中文]]></category>
		<category><![CDATA[文本分类]]></category>
		<category><![CDATA[腾讯云]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=12796</guid>

					<description><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p>为 training 数据做标注，这可能是一个艰巨的任务，也可能是一个有捷径的任务。<br />
有时候，我们可以依据一些已知的规则来标注文本，比如不同的数据是从不同的来源获取到的，从来源可以知道它们所属的类别，这是一个捷径。不过我这里不具备这样的条件。<br />
我的数据来源是网上的各种新闻，不是某些专业领域的数据，这种比较常见的文本分类任务，可以利用国内的几大云服务商提供的免费接口来完成。阿里云、腾讯云都有这样的接口。<br />
以腾讯云为例，其&#8220;人工智能&#8594;<a href="https://cloud.tencent.com/product/nlp" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">自然语言处理</span></a>&#8221;产品提供了文本分类功能：</p>
<blockquote>
<div>
		文本分类接口能够对用户输入的文本进行自动分类，将其映射到具体的类目上，用户只需要提供待分类的文本，而无需关注具体实现。</div>
<div>
		该功能基于千亿级大规模互联网语料和LSTM、BERT等深度神经网络模型进行训练，并持续迭代更新，以保证效果不断提升。</div>
<div>
		目前已提供：</div>
<div>
		● 通用领域分类体系，包括15个分类类目，分别是汽车、科技、健康、体育、旅行、教育、职业、文化、军事、房产、娱乐、女性、奥运、财经以及其他，适用于通用的场景。</div>
<div>
		● 新闻领域分类体系，包括37个一级分类类目，285个二级分类（详细请见 类目体系映射表），已应用于腾讯新闻的文章分类。</div>
<div>
		更多垂直领域的分类体系即将推出，敬请期待。</div>
<div>
		默认接口请求频率限制：20次/秒。</div>
</blockquote>
<div>
	该API每天有50万次免费调用额度，用来标注数据够用了：<br />
	<a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><img decoding="async" alt="tencent cloud nlp free resource" src="https://www.codelast.com/wp-content/uploads/2020/07/tencent_nlp_free_resource.png" style="width: 375px; height: 81px;" /></a><br />
	如果你对这个接口的分类结果准确性有疑虑的话，可以亲自拿一些新闻的文本试一试，就会发现它的效果真的不错，完全可以用来当作人工标注的结果了，毕竟是大厂出品嘛。<br />
	<span id="more-12796"></span><br />
	同理，阿里云也有类似的接口。作为电商界的龙头，阿里云的文本分类接口不仅适用于新闻资讯领域类目体系，还能用于电商领域类目体系。所以，如果你的文本是电商领域的，可以试试阿里云。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	下面，就来看看怎么薅腾讯云的羊毛。注册腾讯云账号、开通自然语言处理接口的权限，这些就不用说了，自己在网页上点几下就可以完成。<br />
	<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;测试接口<br />
	腾讯云NLP接口提供了一个在线测试的网页，从<a href="https://cloud.tencent.com/document/product/271/35496" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">这个</span></a>链接可以进去（&#8220;<span style="color:#0000ff;">点击调试</span>&#8221;）：</div>
<p><img decoding="async" alt="tencent cloud nlp debug entrance" src="https://www.codelast.com/wp-content/uploads/2020/07/tencent_nlp_debug_entrance.png" style="width: 700px; height: 137px;" /></p>
<p><span style="color:#0000ff;">进入调试页面：</span><br />
<a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><img decoding="async" alt="" src="https://www.codelast.com/wp-content/uploads/2020/07/tencent_nlp_web_debug.png" style="width: 700px; height: 413px;" /></a><br />
对这个接口：<br />
Region只能选&#8220;华南地区(广州)&#8221;。<br />
Text是待分类的文本，注意<span style="color:#ff0000;">不需要分词</span>。只需要把我们前面清洗过（去掉了HTML tag等内容）的句子拿来用即可。<br />
Flag为&#160;1 表示通用领域，为 2 表示新闻领域。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb3/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p>为 training 数据做标注，这可能是一个艰巨的任务，也可能是一个有捷径的任务。<br />
有时候，我们可以依据一些已知的规则来标注文本，比如不同的数据是从不同的来源获取到的，从来源可以知道它们所属的类别，这是一个捷径。不过我这里不具备这样的条件。<br />
我的数据来源是网上的各种新闻，不是某些专业领域的数据，这种比较常见的文本分类任务，可以利用国内的几大云服务商提供的免费接口来完成。阿里云、腾讯云都有这样的接口。<br />
以腾讯云为例，其&ldquo;人工智能&rarr;<a href="https://cloud.tencent.com/product/nlp" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">自然语言处理</span></a>&rdquo;产品提供了文本分类功能：</p>
<blockquote>
<div>
		文本分类接口能够对用户输入的文本进行自动分类，将其映射到具体的类目上，用户只需要提供待分类的文本，而无需关注具体实现。</div>
<div>
		该功能基于千亿级大规模互联网语料和LSTM、BERT等深度神经网络模型进行训练，并持续迭代更新，以保证效果不断提升。</div>
<div>
		目前已提供：</div>
<div>
		● 通用领域分类体系，包括15个分类类目，分别是汽车、科技、健康、体育、旅行、教育、职业、文化、军事、房产、娱乐、女性、奥运、财经以及其他，适用于通用的场景。</div>
<div>
		● 新闻领域分类体系，包括37个一级分类类目，285个二级分类（详细请见 类目体系映射表），已应用于腾讯新闻的文章分类。</div>
<div>
		更多垂直领域的分类体系即将推出，敬请期待。</div>
<div>
		默认接口请求频率限制：20次/秒。</div>
</blockquote>
<div>
	该API每天有50万次免费调用额度，用来标注数据够用了：<br />
	<a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><img decoding="async" alt="tencent cloud nlp free resource" src="https://www.codelast.com/wp-content/uploads/2020/07/tencent_nlp_free_resource.png" style="width: 375px; height: 81px;" /></a><br />
	如果你对这个接口的分类结果准确性有疑虑的话，可以亲自拿一些新闻的文本试一试，就会发现它的效果真的不错，完全可以用来当作人工标注的结果了，毕竟是大厂出品嘛。<br />
	<span id="more-12796"></span><br />
	同理，阿里云也有类似的接口。作为电商界的龙头，阿里云的文本分类接口不仅适用于新闻资讯领域类目体系，还能用于电商领域类目体系。所以，如果你的文本是电商领域的，可以试试阿里云。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	下面，就来看看怎么薅腾讯云的羊毛。注册腾讯云账号、开通自然语言处理接口的权限，这些就不用说了，自己在网页上点几下就可以完成。<br />
	<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;测试接口<br />
	腾讯云NLP接口提供了一个在线测试的网页，从<a href="https://cloud.tencent.com/document/product/271/35496" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">这个</span></a>链接可以进去（&ldquo;<span style="color:#0000ff;">点击调试</span>&rdquo;）：</div>
<p><img decoding="async" alt="tencent cloud nlp debug entrance" src="https://www.codelast.com/wp-content/uploads/2020/07/tencent_nlp_debug_entrance.png" style="width: 700px; height: 137px;" /></p>
<p><span style="color:#0000ff;">进入调试页面：</span><br />
<a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><img decoding="async" alt="" src="https://www.codelast.com/wp-content/uploads/2020/07/tencent_nlp_web_debug.png" style="width: 700px; height: 413px;" /></a><br />
对这个接口：<br />
Region只能选&ldquo;华南地区(广州)&rdquo;。<br />
Text是待分类的文本，注意<span style="color:#ff0000;">不需要分词</span>。只需要把我们前面清洗过（去掉了HTML tag等内容）的句子拿来用即可。<br />
Flag为&nbsp;1 表示通用领域，为 2 表示新闻领域。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
接口返回的数据是JSON格式，FirstClassName 是一级分类的名称，SecondClassName 是二级分类的名称。<br />
调试页面还提供了&ldquo;代码生成&rdquo;功能，Java、Python、PHP、Go等都有，支持非常全面。选一个你熟悉的语言，就可以在代码里实现了。</p>
<p>由于免费的接口的QPS上限为20次/秒，所以并行什么的就不要想了，单线程就能跑满。<br />
通过腾讯云的接口，我们能在半天内为几十万条文本打上标签，再整理成 fastText 规定的格式，就可以训练模型了。<br />
如果觉得50万条都不够多，可以注册多个腾讯云账号来薅羊毛，或者用几天的时间累积够标注数据。</p>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 使用 fastText 做中文文本分类(2)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb2/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb2/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 29 Jul 2020 09:46:54 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[fastText]]></category>
		<category><![CDATA[HanLP]]></category>
		<category><![CDATA[中文]]></category>
		<category><![CDATA[文本分类]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=12777</guid>

					<description><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p>做好文本预处理，才能输入fastText训练一个效果好的模型出来。</p>
<p><span style="background-color: rgb(255, 255, 0);">✓</span>&#160;原文示例<br />
有时我们拿到的源数据是很粗糙的，带有很多会影响模型效果的内容，例如下面这样：</p>
<blockquote><p>
	&#60;p&#62;罗望子，是豆科酸豆属唯一的种，是热带乔木，原产于东部非洲，包括马达加斯加落叶森林，但已被引入热带亚洲、拉丁美洲和加勒比海。柽柳是中国海南省三亚的一种城市树木。罗望子最适合生长在温度高、日照长、气候干燥、干湿季节分明的地区。&#60;/p&#62;&#60;p&#62;&#60;img src=&#34;http://p0.qhimg.com/t014b83dc78c7cc5000.jpg?size=741x320&#34;/&#62;&#60;br /&#62;&#60;/p&#62;&#60;p&#62;罗望子富含糖、乙酸、酒石酸、甲酸、柠檬酸等成分，主要用于调味品、饮料、果酱等食品领域。吃一点罗望子有很多好处。当我们吃罗望子时，罗望子中含有的多糖是一种非常好的抗光物质。当我们吃这种物质时，它可以防止紫外线辐射伤害皮肤。通常吃一点罗望子，饭前吃一点罗望子可以增进食欲，改善我们的饮食质量。在炎热的夏日，吃一点罗望子可以生津止渴，清热解毒，降低中暑的风险。&#60;/p&#62;&#60;p&#62;&#60;img src=&#34;http://p1.qhimg.com/t01ecdbbc26c329a78b.jpg?size=533x409&#34;/&#62;&#60;br /&#62;&#60;/p&#62;&#60;p&#62;罗望子种子含有丰富的抗氧化物质。多吃罗望子籽可以延缓人体衰老，保持皮肤湿润有光泽。罗望子种子还含有一些清热解毒、消炎的物质，可以帮助我们的人体抵抗一些有害细菌，保护我们的健康。</p></blockquote>
<div>
	这里面不仅带有URL、大量的HTML标签，而且还有标点符号等，这些都要清洗掉。<br />
	<span id="more-12777"></span><br />
	<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;清除掉HTML标签、URL<br />
	这里给出Java版的一个实现(从网上借鉴来的)，它们并不完善，但是够用了：
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="java language-java hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">&#160;&#160;&#160;&#160;<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">/**
&#160;&#160;&#160;&#160;&#160;*&#160;移除一个字符串中的HTML标签。
&#160;&#160;&#160;&#160;&#160;*
&#160;&#160;&#160;&#160;&#160;*&#160;<span class="hljs-doctag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">@param</span>&#160;inputStr&#160;输入的字符串。
&#160;&#160;&#160;&#160;&#160;*&#160;<span class="hljs-doctag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">@return</span>&#160;移除了HTML标签之后的字符串。
&#160;&#160;&#160;&#160;&#160;*/</span>
&#160;&#160;&#160;&#160;<span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">private</span>&#160;String&#160;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">removeHtmlTags</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(String&#160;inputStr)</span>&#160;</span>{
&#160;&#160;&#160;&#160;&#160;&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">if</span>&#160;(StringUtils.isEmpty(inputStr))&#160;{
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">return</span>&#160;inputStr;
&#160;&#160;&#160;&#160;&#160;&#160;}
&#160;&#160;&#160;&#160;&#160;&#160;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">return</span>&#160;inputStr.replaceAll(</code></pre></section></div>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb2/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p>做好文本预处理，才能输入fastText训练一个效果好的模型出来。</p>
<p><span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;原文示例<br />
有时我们拿到的源数据是很粗糙的，带有很多会影响模型效果的内容，例如下面这样：</p>
<blockquote><p>
	&lt;p&gt;罗望子，是豆科酸豆属唯一的种，是热带乔木，原产于东部非洲，包括马达加斯加落叶森林，但已被引入热带亚洲、拉丁美洲和加勒比海。柽柳是中国海南省三亚的一种城市树木。罗望子最适合生长在温度高、日照长、气候干燥、干湿季节分明的地区。&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://p0.qhimg.com/t014b83dc78c7cc5000.jpg?size=741x320&quot;/&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;罗望子富含糖、乙酸、酒石酸、甲酸、柠檬酸等成分，主要用于调味品、饮料、果酱等食品领域。吃一点罗望子有很多好处。当我们吃罗望子时，罗望子中含有的多糖是一种非常好的抗光物质。当我们吃这种物质时，它可以防止紫外线辐射伤害皮肤。通常吃一点罗望子，饭前吃一点罗望子可以增进食欲，改善我们的饮食质量。在炎热的夏日，吃一点罗望子可以生津止渴，清热解毒，降低中暑的风险。&lt;/p&gt;&lt;p&gt;&lt;img src=&quot;http://p1.qhimg.com/t01ecdbbc26c329a78b.jpg?size=533x409&quot;/&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;罗望子种子含有丰富的抗氧化物质。多吃罗望子籽可以延缓人体衰老，保持皮肤湿润有光泽。罗望子种子还含有一些清热解毒、消炎的物质，可以帮助我们的人体抵抗一些有害细菌，保护我们的健康。</p></blockquote>
<div>
	这里面不仅带有URL、大量的HTML标签，而且还有标点符号等，这些都要清洗掉。<br />
	<span id="more-12777"></span><br />
	<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;清除掉HTML标签、URL<br />
	这里给出Java版的一个实现(从网上借鉴来的)，它们并不完善，但是够用了：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="java language-java hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;移除一个字符串中的HTML标签。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span class="hljs-doctag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">@param</span>&nbsp;inputStr&nbsp;输入的字符串。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span class="hljs-doctag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">@return</span>&nbsp;移除了HTML标签之后的字符串。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">private</span>&nbsp;String&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">removeHtmlTags</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(String&nbsp;inputStr)</span>&nbsp;</span>{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">if</span>&nbsp;(StringUtils.isEmpty(inputStr))&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">return</span>&nbsp;inputStr;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">return</span>&nbsp;inputStr.replaceAll(<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;&lt;[^&gt;]*&gt;&quot;</span>,&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;&quot;</span>);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">/**
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;移除一个字符串中的URL。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span class="hljs-doctag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">@param</span>&nbsp;inputStr&nbsp;输入的字符串。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;<span class="hljs-doctag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">@return</span>&nbsp;移除了URL之后的字符串。
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">private</span>&nbsp;String&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">removeUrl</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(String&nbsp;inputStr)</span>&nbsp;</span>{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;urlPattern&nbsp;=&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;((https?|ftp|gopher|telnet|file|Unsure|http):((//)|(\\\$$)+[\\w\\d:#@%/;$()~_?+-=\\\\.&amp;]*)&quot;</span>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pattern&nbsp;p&nbsp;=&nbsp;Pattern.compile(urlPattern,&nbsp;Pattern.CASE_INSENSITIVE);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Matcher&nbsp;m&nbsp;=&nbsp;p.matcher(inputStr);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;sb&nbsp;=&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">new</span>&nbsp;StringBuffer(inputStr.length());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">while</span>&nbsp;(m.find())&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;m.appendReplacement(sb,&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;&quot;</span>);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">return</span>&nbsp;sb.length()&nbsp;==&nbsp;<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">0</span>&nbsp;?&nbsp;inputStr&nbsp;:&nbsp;sb.toString();
&nbsp;&nbsp;&nbsp;&nbsp;}
</code></pre>
</section>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	以前面的内容为例，依次经过上面两个方法处理后，得到的结果是：</div>
<blockquote>
<div>
		罗望子，是豆科酸豆属唯一的种，是热带乔木，原产于东部非洲，包括马达加斯加落叶森林，但已被引入热带亚洲、拉丁美洲和加勒比海。柽柳是中国海南省三亚的一种城市树木。罗望子最适合生长在温度高、日照长、气候干燥、干湿季节分明的地区。罗望子富含糖、乙酸、酒石酸、甲酸、柠檬酸等成分，主要用于调味品、饮料、果酱等食品领域。吃一点罗望子有很多好处。当我们吃罗望子时，罗望子中含有的多糖是一种非常好的抗光物质。当我们吃这种物质时，它可以防止紫外线辐射伤害皮肤。通常吃一点罗望子，饭前吃一点罗望子可以增进食欲，改善我们的饮食质量。在炎热的夏日，吃一点罗望子可以生津止渴，清热解毒，降低中暑的风险。罗望子种子含有丰富的抗氧化物质。多吃罗望子籽可以延缓人体衰老，保持皮肤湿润有光泽。罗望子种子还含有一些清热解毒、消炎的物质，可以帮助我们的人体抵抗一些有害细菌，保护我们的健康。</div>
</blockquote>
<div>
	这样看上去就干净多了。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	除此之外，还有标点符号，以及一些无用的词需要被除掉，这些词对表达文本的主要含义作用不大，比如&ldquo;啊&rdquo;，&ldquo;嘿&rdquo;之类的词，它们一般称为<span style="color:#0000ff;">停用词</span>(stop words)。我们可以从网上下载到常用的停用词表，比如<a href="https://github.com/goto456/stopwords" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">这个</span></a>链接。<br />
	在对文本进行分词之后，出现在停用词表中的，全都过滤掉。</p>
<p>	<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;分词并去除停用词<br />
	Python下比较流行的中文分词器之一是<a href="https://github.com/fxsjy/jieba" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">结巴分词</span></a>：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="python language-python hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">import</span>&nbsp;jieba


my_text&nbsp;=&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#39;罗望子，是豆科酸豆属唯一的种，...&#39;

</span>

<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">#&nbsp;分词</span>
segmented_words&nbsp;=&nbsp;jieba.cut(my_text,&nbsp;cut_all=<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">False</span>)&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">#&nbsp;精确分词模式

</span>

<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">#&nbsp;去除停用词
</span>
<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">for</span>&nbsp;single_word&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">in</span>&nbsp;segmented_words:
&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">#<span class="hljs-doctag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">TODO:</span>&nbsp;去除停用词</span></code></pre>
</section>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	Java版的结巴分词作者已经不维护了，建议换其他的分词器，比如用户量很大的<a href="https://github.com/hankcs/HanLP" rel="noopener noreferrer" target="_blank"><span style="background-color:#fff0f5;">HanLP</span></a>。其使用也非常简单，在Maven项目的 pom.xml&nbsp;中添加：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="xml language-xml hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-tag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">&lt;<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">dependency</span>&gt;</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-tag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">&lt;<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">groupId</span>&gt;</span>com.hankcs<span class="hljs-tag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">&lt;/<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">groupId</span>&gt;</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-tag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">&lt;<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">artifactId</span>&gt;</span>hanlp<span class="hljs-tag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">&lt;/<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">artifactId</span>&gt;</span>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-tag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">&lt;<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">version</span>&gt;</span>portable-1.7.8<span class="hljs-tag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">&lt;/<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">version</span>&gt;</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-tag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">&lt;/<span class="hljs-name" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">dependency</span>&gt;</span></code></pre>
</section>
<p>就可以用了：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="java language-java hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">import</span>&nbsp;com.hankcs.hanlp.seg.common.Term;
<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">import</span>&nbsp;com.hankcs.hanlp.tokenizer.StandardTokenizer;

String&nbsp;myText&nbsp;=&nbsp;<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;罗望子，是豆科酸豆属唯一的种，...&quot;</span>;

List&lt;Term&gt;&nbsp;termList&nbsp;=&nbsp;StandardTokenizer.segment(myText);
<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">for</span>&nbsp;(Term&nbsp;term&nbsp;:&nbsp;termList)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(term.word);&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">//&nbsp;term.word即分出来的每个词</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">//<span class="hljs-doctag" style="font-size: inherit; color: inherit; line-height: inherit; margin: 0px; padding: 0px; word-wrap: inherit !important; word-break: inherit !important;">TODO:</span>&nbsp;去除停用词</span>
}
</code></pre>
</section>
<p>现在得到的是分好的词，并且把停用词等杂七杂八的东西都去掉了，也许对某些情况很糟糕的文本，还会有漏网之鱼，但对一般情况来说基本上够用了。<br />
	不同的分词器分出来的词结果不尽相同，这里以Java版为例，得到：</div>
<blockquote>
<div>
		罗 望子 豆科 酸 豆 属 唯一 种 热带 乔木 原产 东部 非洲 包括 马达加斯加 落 叶森林 已 引入 热带 亚洲 拉丁美洲 加勒比海 柽 柳是 中国 海南省 三亚 种 城市 树木 罗 望子 最 适合 生长 温度 高 日照 长 气候 干燥 干湿 季节 分明 地区 罗 望子 富含 糖 乙酸 酒石酸 甲酸 柠檬酸 成分 用于 调味品 饮料 果酱 食品 领域 吃 一点 罗 望子 很多 好处 吃 罗 望子 时 罗 望子 中 含有 多糖 种 好 抗光 物质 吃 物质 时 紫外线 辐射 伤害 皮肤 吃 一点 罗 望子 饭前 吃 一点 罗 望子 增进 食欲 改善 饮食 质量 炎热 夏日 吃 一点 罗 望子 生津止渴 清热 解毒 降低 中暑 风险 罗 望子 种子 含有 抗氧化 物质 吃 罗 望子 籽 延缓 人体 衰老 皮肤 湿润 光泽 罗 望子 种子 还 含有 清热 解毒 消炎 物质 人体 抵抗 有害 细菌 保护 健康</div>
</blockquote>
<div>
	为了清晰展示结果，词与词之间用空格隔开了。<br />
	如果对分词结果不满意，比如人名，特殊物品名，可以为分词器添加字典，让分词器识别它们。这些调优的工作就不详述了。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;文本标注<br />
	fastText对训练数据的格式要求是这样的：</p>
<blockquote>
<p>
			<span style="color:#0000ff;">__label__健康</span> 罗 望子 豆科 酸 豆 属 唯一 种 热带 乔木 原产 东部 非洲 包括 马达加斯加 落 叶森林 已 引入 热带 亚洲 拉丁美洲 加勒比海 柽 柳是 中国 海南省 三亚 种 城市 树木 罗 望子 最 适合 生长 温度 高 日照 长 气候 干燥 干湿 季节 分明 地区 罗 望子 富含 糖 乙酸 酒石酸 甲酸 柠檬酸 成分 用于 调味品 饮料 果酱 食品 领域 吃 一点 罗 望子 很多 好处 吃 罗 望子 时 罗 望子 中 含有 多糖 种 好 抗光 物质 吃 物质 时 紫外线 辐射 伤害 皮肤 吃 一点 罗 望子 饭前 吃 一点 罗 望子 增进 食欲 改善 饮食 质量 炎热 夏日 吃 一点 罗 望子 生津止渴 清热 解毒 降低 中暑 风险 罗 望子 种子 含有 抗氧化 物质 吃 罗 望子 籽 延缓 人体 衰老 皮肤 湿润 光泽 罗 望子 种子 还 含有 清热 解毒 消炎 物质 人体 抵抗 有害 细菌 保护 健康</p>
</blockquote>
<p>	每两个字符串之间都用空格隔开，以&ldquo;<span style="color:#0000ff;">__label__</span>&rdquo;开头的（前后均为双下划线）是后面文本的标签，这里可以有多个标签，比如&ldquo;__label__健康 __label__生活&rdquo;，也是用空格分隔开。前面说过，本文以1个标签举例，所以这里只有1个。<br />
	这是文本预处理的最后一步，完成之后就可以把数据喂给fastText训练出一个模型啦。<br />
	比如说上面分好词的文本，我们要为它标注一个类别（例如&ldquo;健康&rdquo;）。<br />
	然鹅，我们难道用人工肉眼看的方法来标注吗？并且，类别有哪些，我怎么知道？<br />
	就算有一目十行的能力，看瞎我的钛合金狗眼，我一天也标不了10万条数据啊！<br />
	欲知解决方法，请看下一篇文章。</p>
<p>	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
		<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb2/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 使用 fastText 做中文文本分类(1)</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb1/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb1/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Wed, 29 Jul 2020 09:46:10 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[fastText]]></category>
		<category><![CDATA[中文]]></category>
		<category><![CDATA[文本分类]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=12754</guid>

					<description><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" target="_blank" rel="noopener noreferrer"><span style="background-color:#ffa07a;">这里</span></a>。</p>
<p><span style="background-color: rgb(255, 255, 0);">✓</span>&#160;什么是&#8220;文本分类&#8221;</p>
<blockquote>
<p>
		它是图书馆学， 信息学和计算机科学中的一个问题。其任务是将一个文档分配到一个或者多个类别中。</p>
</blockquote>
<p>举例：</p>
<table selecttype="cells" style="border-collapse: collapse;">
<colgroup>
<col style="width: 550px;" width="550" />
<col style="width: 107px;" width="107" />
	</colgroup>
<tbody>
<tr height="24" style="height: 24px;">
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; white-space: nowrap; text-align: center; font-family: &#34;Microsoft YaHei&#34;; font-size: 10pt; background-color: rgb(223, 248, 255); border-width: 0.5pt; border-style: solid; border-color: rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">文本</font></td>
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; white-space: nowrap; text-align: center; font-family: &#34;Microsoft YaHei&#34;; font-size: 10pt; background-color: rgb(223, 248, 255); border-width: 0.5pt; border-style: solid; border-color: rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">类别</font></td>
</tr>
<tr height="24" style="height: 24px;">
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; font-family: &#34;Microsoft YaHei&#34;; font-size: 10pt; border-top: 0.5pt solid rgb(0, 0, 0); border-right: 0.5pt solid rgb(0, 0, 0); border-left: 0.5pt solid rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">瑞幸咖啡今日发布声明称，瑞幸咖啡公司将于6月29日在纳斯达克停牌，并进行退市备案。声明表示，在国内消费市场方面，瑞幸咖啡全国4000多家门店将正常运营，近3万名员工仍将一如既往的为用户提供优质产品和服务。公司衷心感谢广大消费者的支持厚爱，并再次为事件造成的恶劣影响向社会各界诚挚道歉。</font></td>
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; white-space: nowrap; text-align: center; font-family: &#34;Microsoft YaHei&#34;; font-size: 10pt; border-top: 0.5pt solid rgb(0, 0, 0); border-right: 0.5pt solid rgb(0, 0, 0); border-left: 0.5pt solid rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">财经</font></td>
</tr>
<tr height="24" style="height: 24px;">
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; font-family: &#34;Microsoft YaHei&#34;; font-size: 10pt; border-width: 0.5pt; border-style: solid; border-color: rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">明朝中后期西南沿海一个重要的问题就是倭寇的骚扰，这个问题本来是有希望被当时的浙江总督用和平的方法解决掉的，但是中途就出了个王本固这个插曲。</font></td>
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; white-space: nowrap; text-align: center; font-family: &#34;Microsoft YaHei&#34;; font-size: 10pt; border-width: 0.5pt; border-style: solid; border-color: rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">历史</font></td>
</tr>
</tbody>
</table>
<p>
其中，&#8220;类别&#8221;是事先定义好的。一段文本可以属于多个类别，例如，第2个例子可以同时属于&#8220;历史&#8221;和&#8220;明朝&#8221;这两个类别。<br />
<span id="more-12754"></span><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;fastText是什么<br />
fastText是Facebook于2016年开源的一个词向量计算和<span style="color:#0000ff;">文本分类</span>工具，官方定义：</p>
<blockquote>
<p>
		Library for efficient text classification and representation learning</p>
</blockquote>
<p>工具如其名，&#8220;fast&#8221;，表明它的速度很快。<br />
fastText应用很广泛，本文以<span style="color:#0000ff;">只有1个类别</span>的<span style="color:#ff0000;">中文</span>文本分类任务为例，展示如何从源数据开始，到数据处理，到最后完成分类的过程。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&#160;安装fastText<br />
fastText 有一个在命令行直接就能用的可执行程序，也有Python的接口，这两样东西我们都装上。<br />
安装、使用fastText对编译器版本、Python版本都有一定的要求，可以查看fastText网站了解这些信息。</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="bash language-bash hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">wget&#160;https://github.com/facebookresearch/fastText/archive/v0.9.2.zip</code></pre>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb1/" class="read-more">Read More </a></section>]]></description>
										<content:encoded><![CDATA[<p>查看本系列文章合集，请看<a href="https://www.codelast.com/?p=12856" target="_blank" rel="noopener noreferrer"><span style="background-color:#ffa07a;">这里</span></a>。</p>
<p><span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;什么是&ldquo;文本分类&rdquo;</p>
<blockquote>
<p>
		它是图书馆学， 信息学和计算机科学中的一个问题。其任务是将一个文档分配到一个或者多个类别中。</p>
</blockquote>
<p>举例：</p>
<table selecttype="cells" style="border-collapse: collapse;">
<colgroup>
<col style="width: 550px;" width="550" />
<col style="width: 107px;" width="107" />
	</colgroup>
<tbody>
<tr height="24" style="height: 24px;">
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; white-space: nowrap; text-align: center; font-family: &quot;Microsoft YaHei&quot;; font-size: 10pt; background-color: rgb(223, 248, 255); border-width: 0.5pt; border-style: solid; border-color: rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">文本</font></td>
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; white-space: nowrap; text-align: center; font-family: &quot;Microsoft YaHei&quot;; font-size: 10pt; background-color: rgb(223, 248, 255); border-width: 0.5pt; border-style: solid; border-color: rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">类别</font></td>
</tr>
<tr height="24" style="height: 24px;">
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; font-family: &quot;Microsoft YaHei&quot;; font-size: 10pt; border-top: 0.5pt solid rgb(0, 0, 0); border-right: 0.5pt solid rgb(0, 0, 0); border-left: 0.5pt solid rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">瑞幸咖啡今日发布声明称，瑞幸咖啡公司将于6月29日在纳斯达克停牌，并进行退市备案。声明表示，在国内消费市场方面，瑞幸咖啡全国4000多家门店将正常运营，近3万名员工仍将一如既往的为用户提供优质产品和服务。公司衷心感谢广大消费者的支持厚爱，并再次为事件造成的恶劣影响向社会各界诚挚道歉。</font></td>
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; white-space: nowrap; text-align: center; font-family: &quot;Microsoft YaHei&quot;; font-size: 10pt; border-top: 0.5pt solid rgb(0, 0, 0); border-right: 0.5pt solid rgb(0, 0, 0); border-left: 0.5pt solid rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">财经</font></td>
</tr>
<tr height="24" style="height: 24px;">
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; font-family: &quot;Microsoft YaHei&quot;; font-size: 10pt; border-width: 0.5pt; border-style: solid; border-color: rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">明朝中后期西南沿海一个重要的问题就是倭寇的骚扰，这个问题本来是有希望被当时的浙江总督用和平的方法解决掉的，但是中途就出了个王本固这个插曲。</font></td>
<td style="empty-cells: show; line-height: normal; vertical-align: middle; outline-width: 0px; overflow-wrap: break-word; word-break: normal; white-space: nowrap; text-align: center; font-family: &quot;Microsoft YaHei&quot;; font-size: 10pt; border-width: 0.5pt; border-style: solid; border-color: rgb(0, 0, 0);">
				<font style="white-space: pre-wrap; font-size: 10pt;">历史</font></td>
</tr>
</tbody>
</table>
<p>
其中，&ldquo;类别&rdquo;是事先定义好的。一段文本可以属于多个类别，例如，第2个例子可以同时属于&ldquo;历史&rdquo;和&ldquo;明朝&rdquo;这两个类别。<br />
<span id="more-12754"></span><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;fastText是什么<br />
fastText是Facebook于2016年开源的一个词向量计算和<span style="color:#0000ff;">文本分类</span>工具，官方定义：</p>
<blockquote>
<p>
		Library for efficient text classification and representation learning</p>
</blockquote>
<p>工具如其名，&ldquo;fast&rdquo;，表明它的速度很快。<br />
fastText应用很广泛，本文以<span style="color:#0000ff;">只有1个类别</span>的<span style="color:#ff0000;">中文</span>文本分类任务为例，展示如何从源数据开始，到数据处理，到最后完成分类的过程。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;安装fastText<br />
fastText 有一个在命令行直接就能用的可执行程序，也有Python的接口，这两样东西我们都装上。<br />
安装、使用fastText对编译器版本、Python版本都有一定的要求，可以查看fastText网站了解这些信息。</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="bash language-bash hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">wget&nbsp;https://github.com/facebookresearch/fastText/archive/v0.9.2.zip
unzip&nbsp;v0.9.2.zip
<span class="hljs-built_in" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">cd</span>&nbsp;fastText-0.9.2
make
pip&nbsp;install&nbsp;.
</code></pre>
</section>
<p>本文写作时，fastText的最新版是 0.9.2，如果版本有更新，上面的命令要跟着修改。<br />
我们会看到当前目录下生成了一个名为&ldquo;fasttext&rdquo;的可执行程序。这样，fastText就可以开始用了。但这只是万里长征第一步，之后的文本预处理、类别标注才是最麻烦的。</p>
<p><span style="background-color: rgb(255, 255, 0);">✓</span>&nbsp;文本分类的流程<br />
并不是我们有了文本数据（一行一个字符串），就能直接喂给fastText训练出来一个分类模型了，我们不仅要对数据进行一些细致的清洗，还要把输入fastText的数据做成它要求的格式，这样它才能识别并训练出模型。</p>
<p>简单地说，文本分类的过程主要由以下步骤构成：<br />
● 对待分类的文本数据做预处理。例如：去掉文本里的乱七八糟的字符、标点符号，等等。并且，由于中文不像英文有天然的空格做为词与词之间的分隔符，因此，我们只能使用分词器来对中文句子进行分词。<br />
● 对文本进行标注。fastText训练的是有监督的文本分类模型，你得先给它一堆例子：什么样的文本，对应的正确分类是什么。这样它才能学出一个模型，用于预测一个没有见过的文本的类别。标注可以由人工完成（效率低，一般不现实），也可以从一些可信的数据源获取文本的正确分类。<br />
● 把处理好的文本数据拆分成training集和validation集，training集用于训练模型，validation集用于检验模型效果。<br />
● 用fastText训练training集得到一个模型，用validation集检验模型效果，如果效果不好，调整模型训练的参数训练一个新模型继续检验效果。</p>
<p>下面，就依次描述以上各项。请看下一篇文章。</p>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e4%bd%bf%e7%94%a8-fasttext-%e5%81%9a%e4%b8%ad%e6%96%87%e6%96%87%e6%9c%ac%e5%88%86%e7%b1%bb1/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 调戏了一番度娘&quot;最先进&quot;的PLATO-2预训练模型之后，我还是回到了和人类交谈...</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%b0%83%e6%88%8f%e4%ba%86%e4%b8%80%e7%95%aa%e5%ba%a6%e5%a8%98%e6%9c%80%e5%85%88%e8%bf%9b%e7%9a%84plato-2%e9%a2%84%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b%e4%b9%8b%e5%90%8e/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%b0%83%e6%88%8f%e4%ba%86%e4%b8%80%e7%95%aa%e5%ba%a6%e5%a8%98%e6%9c%80%e5%85%88%e8%bf%9b%e7%9a%84plato-2%e9%a2%84%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b%e4%b9%8b%e5%90%8e/#comments</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Mon, 13 Jul 2020 17:35:58 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[NLP]]></category>
		<category><![CDATA[PLATO-2]]></category>
		<category><![CDATA[对话模型]]></category>
		<category><![CDATA[机器学习]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=12698</guid>

					<description><![CDATA[<p><img decoding="async" alt="plato-2 network arch" src="https://www.codelast.com/wp-content/uploads/2020/07/plato_2_network_arch.png" style="width: 660px; height: 268px;" /><br />
（莫慌，这图是拿出来撑场面的，我可能和你一样看不懂）</p>
<p>前言：这是一篇很不严肃的实验文章。每一个会修电脑的人，都可以很容易地照着本文的描述，自己去操作一遍。</p>
<p>大概一周前，百度不是发布了一个&#8220;取得重要进展&#8221;的对话生成网络 PLATO-2&#160;吗？我当时一看到那消息，精神就来了，为什么？这得先从解释一下&#8220;这玩意是干什么用的&#8221;说起&#8212;&#8212;毕竟，这篇文章要让每一个群众都能看得懂，大家好才是真的好。</p>
<blockquote>
<p>
		近日，百度发布对话生成网络 PLATO-2，宣布在开放域对话生成模型上迎来重要进展。PLATO-2 承袭 PLATO 隐变量进行回复多样化生成特性，模型参数高达 16 亿，涵盖中英文版本，可就开放域话题深度畅聊。实验结果显示，PLATO-2 中英文对话效果已超越谷歌 Meena、微软小冰和 Facebook Blender 等先进模型。</p>
</blockquote>
<p>咳咳，这些专业术语说的是什么鬼？<br />
如果你完全看不明白这段话，只需要知道：它说的是和<a href="https://zh.wikipedia.org/wiki/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86" rel="noopener noreferrer" target="_blank">NLP</a>（自然语言处理，一门机器学习的分支学科）相关的一些东西。<br />
可能有的人只听说过这段话里提到的&#8220;微软小冰&#8221;&#8212;&#8212;她的主要功能就是一个【聊天机器人】，和小米的&#8220;小爱同学&#8221;颇为相似。<br />
&#8220;小爱同学，帮我把空调打开！&#8221; &#8220;好的，开啦！&#8221;<br />
&#8212;&#8212;相信这样的场景，早已飞入我国千千万万寻常百姓家。<br />
所以，百度发布的这个 PLATO-2，它可以用来做&#8220;小爱同学&#8221;的大脑，也就是最核心的那一块功能。不过现实中的&#8220;小爱同学&#8221;远比这个复杂，在这里只是做一个比喻而已。<br />
<span id="more-12698"></span><!--more--><br />
其实我对NLP也是一窍不通，但是我却算是半个<a href="https://www.codelast.com/?p=12576">英语学习</a>爱好者，每周几乎都要在<a href="http://cambly.com/invite/DZZZ" rel="noopener noreferrer" target="_blank">Cambly</a>平台上和native English speaker对话交流两次。另外，2020年1月的时候，Google发布了一个号称是技术极其牛B的聊天机器人：<a href="https://www.codelast.com/?p=11992">Meena</a>，我做梦都想能把花在<a href="http://cambly.com/invite/DZZZ" rel="noopener noreferrer" target="_blank">Cambly</a>上练口语的钱给省下来啊！苦于Google只是写了篇文章把Meena推到众人面前，却没有提供任何代码以及demo，所以当我看到度娘说&#8220;我整了一个比Meena还要牛B的机器人&#8221;的时候，我简直要感动哭了&#8212;&#8212;度娘，你是我的救世主！<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
还等什么？赶紧把这个机器人的代码跑起来啊！等不及了我马上就要上车！<br />
2话不说，找到PLATO-2的<a href="https://github.com/PaddlePaddle/Knover" rel="noopener noreferrer" target="_blank">GitHub</a>地址，checkout下来，看了一眼 README，貌似开箱即可用，我的心情乐开了花。<br />
看一下运行PLATO-2的要求：</p>
<pre style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, &#34;Liberation Mono&#34;, Menlo, monospace; font-size: 13.6px; margin-top: 0px; margin-bottom: 16px; overflow-wrap: normal; padding: 16px; overflow: auto; line-height: 1.45; background-color: rgb(246, 248, 250); border-radius: 6px; color: rgb(36, 41, 46);">
<code style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, &#34;Liberation Mono&#34;, Menlo, monospace; font-size: 13.6px; padding: 0px; margin: 0px; background: initial; border-radius: 6px; word-break: normal; border: 0px; display: inline; overflow: visible; line-height: inherit; overflow-wrap: normal;">- python &#62;= 3.7.0
- paddlepaddle-gpu &#62;= 1.8.1
- numpy
- sentencepiece
- termcolor</code></pre>
<p>没有什么过多的依赖，这很好。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%b0%83%e6%88%8f%e4%ba%86%e4%b8%80%e7%95%aa%e5%ba%a6%e5%a8%98%e6%9c%80%e5%85%88%e8%bf%9b%e7%9a%84plato-2%e9%a2%84%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b%e4%b9%8b%e5%90%8e/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" alt="plato-2 network arch" src="https://www.codelast.com/wp-content/uploads/2020/07/plato_2_network_arch.png" style="width: 660px; height: 268px;" /><br />
（莫慌，这图是拿出来撑场面的，我可能和你一样看不懂）</p>
<p>前言：这是一篇很不严肃的实验文章。每一个会修电脑的人，都可以很容易地照着本文的描述，自己去操作一遍。</p>
<p>大概一周前，百度不是发布了一个&ldquo;取得重要进展&rdquo;的对话生成网络 PLATO-2&nbsp;吗？我当时一看到那消息，精神就来了，为什么？这得先从解释一下&ldquo;这玩意是干什么用的&rdquo;说起&mdash;&mdash;毕竟，这篇文章要让每一个群众都能看得懂，大家好才是真的好。</p>
<blockquote>
<p>
		近日，百度发布对话生成网络 PLATO-2，宣布在开放域对话生成模型上迎来重要进展。PLATO-2 承袭 PLATO 隐变量进行回复多样化生成特性，模型参数高达 16 亿，涵盖中英文版本，可就开放域话题深度畅聊。实验结果显示，PLATO-2 中英文对话效果已超越谷歌 Meena、微软小冰和 Facebook Blender 等先进模型。</p>
</blockquote>
<p>咳咳，这些专业术语说的是什么鬼？<br />
如果你完全看不明白这段话，只需要知道：它说的是和<a href="https://zh.wikipedia.org/wiki/%E8%87%AA%E7%84%B6%E8%AF%AD%E8%A8%80%E5%A4%84%E7%90%86" rel="noopener noreferrer" target="_blank">NLP</a>（自然语言处理，一门机器学习的分支学科）相关的一些东西。<br />
可能有的人只听说过这段话里提到的&ldquo;微软小冰&rdquo;&mdash;&mdash;她的主要功能就是一个【聊天机器人】，和小米的&ldquo;小爱同学&rdquo;颇为相似。<br />
&ldquo;小爱同学，帮我把空调打开！&rdquo; &ldquo;好的，开啦！&rdquo;<br />
&mdash;&mdash;相信这样的场景，早已飞入我国千千万万寻常百姓家。<br />
所以，百度发布的这个 PLATO-2，它可以用来做&ldquo;小爱同学&rdquo;的大脑，也就是最核心的那一块功能。不过现实中的&ldquo;小爱同学&rdquo;远比这个复杂，在这里只是做一个比喻而已。<br />
<span id="more-12698"></span><!--more--><br />
其实我对NLP也是一窍不通，但是我却算是半个<a href="https://www.codelast.com/?p=12576">英语学习</a>爱好者，每周几乎都要在<a href="http://cambly.com/invite/DZZZ" rel="noopener noreferrer" target="_blank">Cambly</a>平台上和native English speaker对话交流两次。另外，2020年1月的时候，Google发布了一个号称是技术极其牛B的聊天机器人：<a href="https://www.codelast.com/?p=11992">Meena</a>，我做梦都想能把花在<a href="http://cambly.com/invite/DZZZ" rel="noopener noreferrer" target="_blank">Cambly</a>上练口语的钱给省下来啊！苦于Google只是写了篇文章把Meena推到众人面前，却没有提供任何代码以及demo，所以当我看到度娘说&ldquo;我整了一个比Meena还要牛B的机器人&rdquo;的时候，我简直要感动哭了&mdash;&mdash;度娘，你是我的救世主！<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
还等什么？赶紧把这个机器人的代码跑起来啊！等不及了我马上就要上车！<br />
2话不说，找到PLATO-2的<a href="https://github.com/PaddlePaddle/Knover" rel="noopener noreferrer" target="_blank">GitHub</a>地址，checkout下来，看了一眼 README，貌似开箱即可用，我的心情乐开了花。<br />
看一下运行PLATO-2的要求：</p>
<pre style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, monospace; font-size: 13.6px; margin-top: 0px; margin-bottom: 16px; overflow-wrap: normal; padding: 16px; overflow: auto; line-height: 1.45; background-color: rgb(246, 248, 250); border-radius: 6px; color: rgb(36, 41, 46);">
<code style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, monospace; font-size: 13.6px; padding: 0px; margin: 0px; background: initial; border-radius: 6px; word-break: normal; border: 0px; display: inline; overflow: visible; line-height: inherit; overflow-wrap: normal;">- python &gt;= 3.7.0
- paddlepaddle-gpu &gt;= 1.8.1
- numpy
- sentencepiece
- termcolor</code></pre>
<p>没有什么过多的依赖，这很好。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
看到 paddlepaddle-gpu&nbsp;的时候，就知道用CPU的机器还不行，可能是inference的速度真的太慢了吧？但我去哪搞一台GPU的机器呢？当然是蹭公司的啦。感谢公司！<br />
为了干净，最好还是在Anaconda下新建一个Python 3.7的 env，然后再安装其他依赖的 Python package。<br />
按百度<a href="https://www.paddlepaddle.org.cn/install/quick#show_info" rel="noopener noreferrer" target="_blank">官方文档</a>就可以很容易搞定一切。<br />
我这里只简要地把几个主要步骤描述一下。<br />
先添加清华的源，再创建为PaddlePaddle创建一个单独的 env：</p>
<blockquote>
<p>
		conda create --name paddle python=3.7<br />
		conda activate paddle</p>
</blockquote>
<p>完了之后，剩下的安装步骤就简单啦：</p>
<blockquote>
<p>
		conda install paddlepaddle-gpu cudatoolkit=10.0<br />
		conda install -c conda-forge sentencepiece<br />
		conda install termcolor</p>
</blockquote>
<p>注意，这里我使用的是 cudatoolkit=10.0，这是因为我机器上的&nbsp;CUDA Version&nbsp;是10.x&nbsp;版本。<br />
最后按百度官方文档测试一下安装上的 PaddlePaddle&nbsp;是否正常，就行了。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
现在可以把 PLATO-2&nbsp;用起来了。把它&nbsp;<a href="https://github.com/PaddlePaddle/Knover" rel="noopener noreferrer" target="_blank">GitHub</a>&nbsp;页面上提供的那两个预训练模型下载到GPU机器上（一个体积小参数少，另一个体积大参数多），按百度的文档里说的，解压到&nbsp;<span style="color:#0000ff;">Knover</span> 目录下：<br />
<a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><img decoding="async" alt="plato-2 pre-trained models" src="https://www.codelast.com/wp-content/uploads/2020/07/plato_2_pre_train_models.png" style="width: 300px; height: 94px;" /></a></p>
<p>下面就可以把&ldquo;交互式对话&rdquo;的程序跑起来了（会加载刚下载的模型）：</p>
<blockquote>
<p>
		cd Knover/plato-2/<br />
		bash ./scripts/32L_plato_interact.sh</p>
</blockquote>
<p>在这里，我用的是体积大参数多的那个模型 32L。<br />
经过一小段时间的耐心等待，模型完全加载好了，看一下显存占用情况，17个G：</p>
<blockquote>
<div>
		+-------------------------------------------------------------------------+</div>
<div>
		| Processes:&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;GPU Memory |</div>
<div>
		|&nbsp; GPU&nbsp; &nbsp; &nbsp; &nbsp;PID&nbsp; &nbsp;Type&nbsp; &nbsp;Process name&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;Usage&nbsp; &nbsp; &nbsp; |</div>
<div>
		|============================================================|</div>
<div>
		|&nbsp; &nbsp; 0&nbsp; &nbsp; &nbsp;38736&nbsp; &nbsp; &nbsp; C&nbsp; &nbsp;python&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;17229MiB |</div>
</blockquote>
<div>
	由于在&nbsp;<span style="color:#0000ff;">32L_plato_interact.sh</span>&nbsp;脚本里默认使用的是第一张卡（export CUDA_VISIBLE_DEVICES=0），所以这里看到的 GPU 0&nbsp;就是了。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	虽然预训练的模型肯定达不到我的期望，不过我还是想看看这个聊天机器人的实际聊天效果怎么样。毕竟百度用了64张V100显卡+3周时间才训练出的模型，我怎么可能去自己训练一个模型呢？我没钱也没资源。</p>
<p>	我试着和机器人聊一下新冠肺炎(<span style="color: rgb(0, 0, 255);">COVID-19</span>)这个主题，但它显然&ldquo;完全不懂&rdquo;，可能是它的训练数据里完全没有这方面的数据吧。不过它不懂也就算了，而且它还一直对 <span style="color:#0000ff;">covid</span>&nbsp;这个它不懂的词纠缠不休，并且还误认成别的东西(pet)。我说东，它说西，最后实在没法聊下去，我只能输入一个 <span style="color:#ff0000;">[NEXT]</span>&nbsp;来让它开始一个新的会话过程。<br />
	下面这张图就是我和机器人的对话过程截图。<br />
	<a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><img decoding="async" alt="chat with plato-2 bot" src="https://www.codelast.com/wp-content/uploads/2020/07/chat_with_baidu_plato_bot.png" style="width: 660px; height: 536px;" /></a><br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	原来我还想着，这个预训练的模型聊天效果要是&ldquo;还行&rdquo;的话，我再给它套一个语音识别的功能，这样就可以真正地和它说话了，现在看来，暂时还是不行。<br />
	于是我又回到了<a href="http://cambly.com/invite/DZZZ" rel="noopener noreferrer" target="_blank">Cambly</a>和真人老外聊天去了。</p>
<p>	后记：从目前的技术发展情况来看，微软小冰、Meena之类的机器人要想在&ldquo;语言学习&rdquo;方面能代替一部分人类教师，真的太难了，如果要有令人直观感受强烈的突破的话，说10年那可能都是少的了。<br />
	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
	转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
	感谢关注我的微信公众号（微信扫一扫）：</p>
<p>
		<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="color: rgb(77, 77, 77); font-size: 13px; width: 200px; height: 200px;" /><br />
		以及我的微信视频号：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
		<img decoding="async" alt="" src="https://www.codelast.com/wechat_shipinhao_qr_code.jpg" style="text-align: center; width: 200px; height: 199px;" /></p>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e8%b0%83%e6%88%8f%e4%ba%86%e4%b8%80%e7%95%aa%e5%ba%a6%e5%a8%98%e6%9c%80%e5%85%88%e8%bf%9b%e7%9a%84plato-2%e9%a2%84%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b%e4%b9%8b%e5%90%8e/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] PyTorch做inference/prediction的时候如何使用GPU</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-pytorch%e5%81%9ainference-prediction%e7%9a%84%e6%97%b6%e5%80%99%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8gpu/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-pytorch%e5%81%9ainference-prediction%e7%9a%84%e6%97%b6%e5%80%99%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8gpu/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Mon, 27 Apr 2020 11:50:56 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[GPU]]></category>
		<category><![CDATA[inference]]></category>
		<category><![CDATA[prediction]]></category>
		<category><![CDATA[PyTorch]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=12047</guid>

					<description><![CDATA[<p>话不多说，直接进入主题。</p>
<p><span style="color:#0000ff;">✔</span> 判断能不能使用GPU<br />
可能有多种原因会导致不能使用GPU，比如PyTorch安装的是CPU版的，显卡驱动没有正确安装等。下面的 if 语句在正常的情况下会返回 True：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#cc7832;">if </span>torch.cuda.is_available():
    <span style="color:#8888c6;">print</span>(<span style="color:#6a8759;">&#39;PyTorch can use GPU on current machine!&#39;</span>)</pre>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);">✔</span>&#160;设置模型使用GPU</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
model = MyModel(*args<span style="color:#cc7832;">, </span>**kwargs)
model.load_state_dict(torch.load(your_model_file_path))
model.eval()  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'DejaVu Sans Mono';">设置成</span><span style="color:#808080;">evaluation</span><span style="color:#808080;font-family:'DejaVu Sans Mono';">模式
</span><span style="color:#cc7832;">if </span>torch.cuda.is_available():
    <span style="color:#8888c6;">print</span>(<span style="color:#6a8759;">&#39;PyTorch can use GPU on current machine!&#39;</span></pre>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-pytorch%e5%81%9ainference-prediction%e7%9a%84%e6%97%b6%e5%80%99%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8gpu/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>话不多说，直接进入主题。</p>
<p><span style="color:#0000ff;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 判断能不能使用GPU<br />
可能有多种原因会导致不能使用GPU，比如PyTorch安装的是CPU版的，显卡驱动没有正确安装等。下面的 if 语句在正常的情况下会返回 True：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#cc7832;">if </span>torch.cuda.is_available():
    <span style="color:#8888c6;">print</span>(<span style="color:#6a8759;">&#39;PyTorch can use GPU on current machine!&#39;</span>)</pre>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;设置模型使用GPU</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
model = MyModel(*args<span style="color:#cc7832;">, </span>**kwargs)
model.load_state_dict(torch.load(your_model_file_path))
model.eval()  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'DejaVu Sans Mono';">设置成</span><span style="color:#808080;">evaluation</span><span style="color:#808080;font-family:'DejaVu Sans Mono';">模式
</span><span style="color:#cc7832;">if </span>torch.cuda.is_available():
    <span style="color:#8888c6;">print</span>(<span style="color:#6a8759;">&#39;PyTorch can use GPU on current machine!&#39;</span>)
    device = torch.device(<span style="color:#6a8759;">&quot;cuda&quot;</span>)
    model.to(device)</pre>
<p>your_model_file_path 是模型文件的路径。<br />
<span id="more-12047"></span><br />
<span style="color: rgb(0, 0, 255);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;inference/predict的时候使用GPU<br />
对一次 inference 来说，假设模型的输入数据为&nbsp;model_input_tensor（torch.Tensor类型），那么计算模型输出的方法是：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#cc7832;">if </span>torch.cuda.is_available():  <span style="color:#808080;"># GPU available
</span><span style="color:#808080;">    </span>model_input_tensor = model_input_tensor.to(torch.device(<span style="color:#6a8759;">&#39;cuda&#39;</span>))
model_output = model(model_input_tensor)  <span style="color:#808080;"># inference</span></pre>
<p>
<span style="color: rgb(0, 0, 255);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;检查程序跑起来之后是不是真的用了GPU<br />
用 nvidia-smi 命令来查看。</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	&nbsp;</p>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-pytorch%e5%81%9ainference-prediction%e7%9a%84%e6%97%b6%e5%80%99%e5%a6%82%e4%bd%95%e4%bd%bf%e7%94%a8gpu/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 总有一天，失业不再遥远</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e6%80%bb%e6%9c%89%e4%b8%80%e5%a4%a9%ef%bc%8c%e5%a4%b1%e4%b8%9a%e4%b8%8d%e5%86%8d%e9%81%a5%e8%bf%9c/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e6%80%bb%e6%9c%89%e4%b8%80%e5%a4%a9%ef%bc%8c%e5%a4%b1%e4%b8%9a%e4%b8%8d%e5%86%8d%e9%81%a5%e8%bf%9c/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Sat, 25 Apr 2020 18:14:12 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[综合]]></category>
		<category><![CDATA[Reinforcement Learning]]></category>
		<category><![CDATA[RL]]></category>
		<category><![CDATA[强化学习]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=11992</guid>

					<description><![CDATA[<p></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="text-align: center;margin: 10px 0%;">
<section style="text-align:left;width:35px;height:35px;margin-left:20px;background-color: rgb(209,95,238);"></section>
<p></p>
<section style="margin-top: -1.5em; border-style: solid; border-width: 1px; border-color: rgb(178, 58, 238); padding: 8px; box-sizing: border-box;">
<section style="border-style: solid; border-width: 3px; border-color: rgb(178, 58, 238); padding: 15px; box-sizing: border-box;">
<p class="brush active" style="letter-spacing: 2px; font-size: 26px; color: rgb(178, 58, 238); min-width: 1px; text-align: left;">
	<span style="font-size:16px;">尽管人类离[通用人工智能]的路还很远，但越来越多新技术的出现，让这条路得以不断加速。</span></p>
</section>
</section>
<section style="width:35px;height:35px;margin-left:auto;margin-top: -1.2em;margin-right:20px;background-color: rgb(209,95,238);"></section>
</section>
</section>
<p></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="margin-right: auto; margin-left: auto; display: flex; justify-content: center; align-items: center;">
<section style="display: flex;flex-direction: row;justify-content: center;align-items: center;">
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
<section style="margin-right: 10px; margin-left: 10px;text-align: center;">
<p class="title active" style=" color: rgb(51, 51, 51); letter-spacing: 1.5px; line-height: 1.75;min-width:1px;">
	​What？强化学习设计芯片？</p>
</section>
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
</section>
</section>
</section>
<p>就这几天的事：Google已经开始用强化学习技术来设计芯片了！<br />
如果说用强化学习来玩游戏、下围棋，甚至用来帮助提升互联网广告的点击率、收入，都不是什么新鲜事的话，那么用强化学习来设计芯片，就也太新鲜了吧？但Google就做到了<span style="color:#0000ff;"><sup>[1]</sup></span>：</p>
<blockquote>
<p>
		我们提出了一种基于学习的芯片布局方法，这是芯片设计过程中最复杂、最耗时的阶段之一。与之前的方法不同，我们的方法具有从过去的经验中学习并随着时间的推移而改进的能力。特别是随着我们对更多的芯片块进行训练，我们的方法在快速生成以前未见过的芯片块的优化布局方面变得更好。为了实现这些结果，我们将芯片布局作为一个强化学习（RL）问题，并训练一个Agent将芯片网表的节点放置到芯片画布上。为了使我们的RL策略能够泛化到未见过的芯片块，我们将表征学习置于预测布局质量的有监督任务中。通过设计一个能够准确预测各种网表及其布局质量的神经架构，我们能够生成丰富的输入网表的特征嵌入。然后，我们使用这个架构作为我们的策略和价值网络的编码器来实现转移学习。我们的目标是将PPA（功率、性能和面积）降到最低，我们表明，在6个小时内，我们的方法可以在现代加速器网表上生成超越人类或可与之相媲美的芯片布局，而现有的基线需要人类专家在循环中进行，并需要几周的时间。</p>
</blockquote>
<p>硬件工程师为之虎躯一颤。<br />
<span id="more-11992"></span><br />
这是我今年看到的第二个跟我多少有点关系，并且又让我马上喊出一句&#8220;卧槽&#8221;的技术应用了。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
在机器学习领域，强化学习可能是目前人类发明的、最接近人类成长过程的机器学习范式了。从婴儿的咿呀学步，到掌握海量知识，人都是在不断接受外界反馈中对自我行为做出修正，而强化学习正是模仿了这一过程。<br />
目前科学家们正在不断拓展强化学习的应用边界，从一开始的相对简单领域，到越来越复杂的工作，都尝试用强化学习来完成。<br />
事实上，在现实世界，真正比较大规模的、普通人摸得着看得见的强化学习应用，还是当属游戏领域的AI玩家，但考虑到游戏受众占总人口数的比例很小，所以客观地说，强化学习并没有像人脸识别、语音识别等机器学习技术一样渗透到民生的方方面面。不过，由于强化学习的可预见潜力很大，我们有理由相信，它会在很多领域代替人类的工作，而这些工作，不是低水平的重复工作，而是需要较高知识储备才能胜任的。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="margin-right: auto; margin-left: auto; display: flex; justify-content: center; align-items: center;">
<section style="display: flex;flex-direction: row;justify-content: center;align-items: center;">
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
<section style="margin-right: 10px; margin-left: 10px;text-align: center;">
<p class="title active" style=" color: rgb(51, 51, 51); letter-spacing: 1.5px; line-height: 1.75;min-width:1px;">
	米娜？你真的可以无障碍聊天？</p>
</section>
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
</section>
</section>
</section>
<p>还是Google，在今年1月的时候发布了一个聊天机器人：Meena<span style="color:#0000ff;"><sup>[2]</sup></span>（&#8220;米娜&#8221;？）。当然，说是发布，其实并没有公开地提供这个服务，也没有App提供下载，Google只是发了篇论文说他们达到了什么样的技术成果。<br />
这个Meena有多牛呢？<br />
举个大家生活中随处可见的例子：无论你是在京东淘宝上购物的时候在线咨询，还是在打各种客服电话的时候接线的是个&#8220;机器人&#8221;，可能都会很容易遇到这样一种情况：只要问题问得不是那么直接，那些&#8220;聊天机器人&#8221;就不知道怎么回答了。<br />
再比如，我家里有一个&#8220;小爱同学&#8221;（小米的智能音箱），我问她&#8220;明天的天气怎么样&#8221;，她能完美回答我；但如果我用和人类随意聊天的方式来和她对话，她马上就会进入懵逼状态：&#8220;哎呀，你说的这个问题小爱不懂&#8221;。<br />
理想和现实的差距，就是人类和市面上所有聊天机器人的差距。<br />
而Google的Meena是一个&#8220;<span style="color:#0000ff;">开放领域聊天机器人</span>&#8221;。开放领域聊天机器人不会仅限于在某个特定领域，而是能够和用户聊近乎所有的话题&#8212;&#8212;这不就是人类的正常表现嘛。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<blockquote>
<p>
		Meena是一个有着26亿参数的端到端神经对话模型，也就是GPT-2模型最大版本（15 亿参数）的1.7倍。通过实验可以看到，Meena 比现有的 SOTA 聊天机器人能够更好地完成对话，对话内容显得更为具体、清楚。</p>
</blockquote>
<p>Google也给出了一些实例，用来说明Meena与人类的对话有多自然。<br />
如果Meena真能达到真人水平，那她一定是我做梦都想拥有的一个chatbot。<br />
我现在每周都在<a href="http://cambly.com/invite/DZZZ" rel="noopener noreferrer" target="_blank"><span style="color: rgb(0, 0, 255);">Cambly</span></a>上和外国人聊天练口语，我当然想把这钱省下来，我曾经也找过英语的chatbot，但没有什么好的结果，在语言学习方面，和人类交流目前还是具有不可替代性。我可以和外国人聊新冠疫情的近况，聊时事政治的发展，但是我和一个chatbot讲这些，它可能当我是傻子（其实它才是傻子）。<br />
所以，如果有一个像Meena那样的chatbot可以和我在开放领域以人类水平用英语聊天，那我真要笑开了花！<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e6%80%bb%e6%9c%89%e4%b8%80%e5%a4%a9%ef%bc%8c%e5%a4%b1%e4%b8%9a%e4%b8%8d%e5%86%8d%e9%81%a5%e8%bf%9c/" class="read-more">Read More </a></p>]]></description>
										<content:encoded><![CDATA[<p></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="text-align: center;margin: 10px 0%;">
<section style="text-align:left;width:35px;height:35px;margin-left:20px;background-color: rgb(209,95,238);"></section>
<p></p>
<section style="margin-top: -1.5em; border-style: solid; border-width: 1px; border-color: rgb(178, 58, 238); padding: 8px; box-sizing: border-box;">
<section style="border-style: solid; border-width: 3px; border-color: rgb(178, 58, 238); padding: 15px; box-sizing: border-box;">
<p class="brush active" style="letter-spacing: 2px; font-size: 26px; color: rgb(178, 58, 238); min-width: 1px; text-align: left;">
	<span style="font-size:16px;">尽管人类离[通用人工智能]的路还很远，但越来越多新技术的出现，让这条路得以不断加速。</span></p>
</section>
</section>
<section style="width:35px;height:35px;margin-left:auto;margin-top: -1.2em;margin-right:20px;background-color: rgb(209,95,238);"></section>
</section>
</section>
<p></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="margin-right: auto; margin-left: auto; display: flex; justify-content: center; align-items: center;">
<section style="display: flex;flex-direction: row;justify-content: center;align-items: center;">
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
<section style="margin-right: 10px; margin-left: 10px;text-align: center;">
<p class="title active" style=" color: rgb(51, 51, 51); letter-spacing: 1.5px; line-height: 1.75;min-width:1px;">
	​What？强化学习设计芯片？</p>
</section>
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
</section>
</section>
</section>
<p>就这几天的事：Google已经开始用强化学习技术来设计芯片了！<br />
如果说用强化学习来玩游戏、下围棋，甚至用来帮助提升互联网广告的点击率、收入，都不是什么新鲜事的话，那么用强化学习来设计芯片，就也太新鲜了吧？但Google就做到了<span style="color:#0000ff;"><sup>[1]</sup></span>：</p>
<blockquote>
<p>
		我们提出了一种基于学习的芯片布局方法，这是芯片设计过程中最复杂、最耗时的阶段之一。与之前的方法不同，我们的方法具有从过去的经验中学习并随着时间的推移而改进的能力。特别是随着我们对更多的芯片块进行训练，我们的方法在快速生成以前未见过的芯片块的优化布局方面变得更好。为了实现这些结果，我们将芯片布局作为一个强化学习（RL）问题，并训练一个Agent将芯片网表的节点放置到芯片画布上。为了使我们的RL策略能够泛化到未见过的芯片块，我们将表征学习置于预测布局质量的有监督任务中。通过设计一个能够准确预测各种网表及其布局质量的神经架构，我们能够生成丰富的输入网表的特征嵌入。然后，我们使用这个架构作为我们的策略和价值网络的编码器来实现转移学习。我们的目标是将PPA（功率、性能和面积）降到最低，我们表明，在6个小时内，我们的方法可以在现代加速器网表上生成超越人类或可与之相媲美的芯片布局，而现有的基线需要人类专家在循环中进行，并需要几周的时间。</p>
</blockquote>
<p>硬件工程师为之虎躯一颤。<br />
<span id="more-11992"></span><br />
这是我今年看到的第二个跟我多少有点关系，并且又让我马上喊出一句&ldquo;卧槽&rdquo;的技术应用了。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
在机器学习领域，强化学习可能是目前人类发明的、最接近人类成长过程的机器学习范式了。从婴儿的咿呀学步，到掌握海量知识，人都是在不断接受外界反馈中对自我行为做出修正，而强化学习正是模仿了这一过程。<br />
目前科学家们正在不断拓展强化学习的应用边界，从一开始的相对简单领域，到越来越复杂的工作，都尝试用强化学习来完成。<br />
事实上，在现实世界，真正比较大规模的、普通人摸得着看得见的强化学习应用，还是当属游戏领域的AI玩家，但考虑到游戏受众占总人口数的比例很小，所以客观地说，强化学习并没有像人脸识别、语音识别等机器学习技术一样渗透到民生的方方面面。不过，由于强化学习的可预见潜力很大，我们有理由相信，它会在很多领域代替人类的工作，而这些工作，不是低水平的重复工作，而是需要较高知识储备才能胜任的。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="margin-right: auto; margin-left: auto; display: flex; justify-content: center; align-items: center;">
<section style="display: flex;flex-direction: row;justify-content: center;align-items: center;">
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
<section style="margin-right: 10px; margin-left: 10px;text-align: center;">
<p class="title active" style=" color: rgb(51, 51, 51); letter-spacing: 1.5px; line-height: 1.75;min-width:1px;">
	米娜？你真的可以无障碍聊天？</p>
</section>
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
</section>
</section>
</section>
<p>还是Google，在今年1月的时候发布了一个聊天机器人：Meena<span style="color:#0000ff;"><sup>[2]</sup></span>（&ldquo;米娜&rdquo;？）。当然，说是发布，其实并没有公开地提供这个服务，也没有App提供下载，Google只是发了篇论文说他们达到了什么样的技术成果。<br />
这个Meena有多牛呢？<br />
举个大家生活中随处可见的例子：无论你是在京东淘宝上购物的时候在线咨询，还是在打各种客服电话的时候接线的是个&ldquo;机器人&rdquo;，可能都会很容易遇到这样一种情况：只要问题问得不是那么直接，那些&ldquo;聊天机器人&rdquo;就不知道怎么回答了。<br />
再比如，我家里有一个&ldquo;小爱同学&rdquo;（小米的智能音箱），我问她&ldquo;明天的天气怎么样&rdquo;，她能完美回答我；但如果我用和人类随意聊天的方式来和她对话，她马上就会进入懵逼状态：&ldquo;哎呀，你说的这个问题小爱不懂&rdquo;。<br />
理想和现实的差距，就是人类和市面上所有聊天机器人的差距。<br />
而Google的Meena是一个&ldquo;<span style="color:#0000ff;">开放领域聊天机器人</span>&rdquo;。开放领域聊天机器人不会仅限于在某个特定领域，而是能够和用户聊近乎所有的话题&mdash;&mdash;这不就是人类的正常表现嘛。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<blockquote>
<p>
		Meena是一个有着26亿参数的端到端神经对话模型，也就是GPT-2模型最大版本（15 亿参数）的1.7倍。通过实验可以看到，Meena 比现有的 SOTA 聊天机器人能够更好地完成对话，对话内容显得更为具体、清楚。</p>
</blockquote>
<p>Google也给出了一些实例，用来说明Meena与人类的对话有多自然。<br />
如果Meena真能达到真人水平，那她一定是我做梦都想拥有的一个chatbot。<br />
我现在每周都在<a href="http://cambly.com/invite/DZZZ" rel="noopener noreferrer" target="_blank"><span style="color: rgb(0, 0, 255);">Cambly</span></a>上和外国人聊天练口语，我当然想把这钱省下来，我曾经也找过英语的chatbot，但没有什么好的结果，在语言学习方面，和人类交流目前还是具有不可替代性。我可以和外国人聊新冠疫情的近况，聊时事政治的发展，但是我和一个chatbot讲这些，它可能当我是傻子（其实它才是傻子）。<br />
所以，如果有一个像Meena那样的chatbot可以和我在开放领域以人类水平用英语聊天，那我真要笑开了花！<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="margin-right: auto; margin-left: auto; display: flex; justify-content: center; align-items: center;">
<section style="display: flex;flex-direction: row;justify-content: center;align-items: center;">
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
<section style="margin-right: 10px; margin-left: 10px;text-align: center;">
<p class="title active" style=" color: rgb(51, 51, 51); letter-spacing: 1.5px; line-height: 1.75;min-width:1px;">
	有生之年的期盼</p>
</section>
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
</section>
</section>
</section>
<p>随着技术的发展，在我有生之年，我一定会看到很多本来&ldquo;不可替代&rdquo;的人类，会因为技术的发展而失业，这当中，或许就包含了我这样的工程师。而技术的目标之一就是节省更大的成本，我也相信在未来几十年，AI在语言学习上一定可以代替人类，和学生进行几乎无障碍的交流对话。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="margin-right: auto; margin-left: auto; display: flex; justify-content: center; align-items: center;">
<section style="display: flex;flex-direction: row;justify-content: center;align-items: center;">
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
<section style="margin-right: 10px; margin-left: 10px;text-align: center;">
<p class="title active" style=" color: rgb(51, 51, 51); letter-spacing: 1.5px; line-height: 1.75;min-width:1px;">
	链接</p>
</section>
<section style="display: flex;flex-direction: column;justify-content: center;align-items: center;">
<section style="width: 43px; height: 3px; background: rgb(255, 0, 0); border-radius: 2px; flex-shrink: 0; box-sizing: border-box;"></section>
<section style="width: 43px; height: 3px; background: rgb(255, 211, 155); border-radius: 2px; flex-shrink: 0; margin-top: 2px; box-sizing: border-box;"></section>
</section>
</section>
</section>
</section>
<p> [1]&nbsp;<a href="https://ai.googleblog.com/2020/04/chip-design-with-deep-reinforcement.html" rel="noopener noreferrer" target="_blank">https://ai.googleblog.com/2020/04/chip-design-with-deep-reinforcement.html</a><br />
[2]&nbsp;<a href="https://ai.googleblog.com/2020/01/towards-conversational-agent-that-can.html" rel="noopener noreferrer" target="_blank">https://ai.googleblog.com/2020/01/towards-conversational-agent-that-can.html</a></p>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e6%80%bb%e6%9c%89%e4%b8%80%e5%a4%a9%ef%bc%8c%e5%a4%b1%e4%b8%9a%e4%b8%8d%e5%86%8d%e9%81%a5%e8%bf%9c/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 强化学习框架 rlpyt 使用GPU训练模型</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e4%bd%bf%e7%94%a8gpu%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e4%bd%bf%e7%94%a8gpu%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b/#comments</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Thu, 16 Apr 2020 18:08:09 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[GPU]]></category>
		<category><![CDATA[rlpyt]]></category>
		<category><![CDATA[强化学习]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=11914</guid>

					<description><![CDATA[<p></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="margin-right: auto; margin-left: auto; display: flex; justify-content: center; align-items: center;">
<section style="width: 100%; border-radius: 5px; border: 1px solid rgb(105, 105, 105); padding: 6px; box-sizing: border-box;">
<section style="width: 100%; border-radius: 5px; border: 1px solid rgb(255, 185, 15); padding: 20px; text-align: justify; box-sizing: border-box;">
<p class="brush active" style=" font-size: 13px; color: rgb(51, 51, 51); letter-spacing: 1.5px; line-height: 1.75;min-width:1px;">
	<a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" style="font-size: medium;" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a><span style="font-size: medium;">&#160;是</span><span style="font-size: medium; color: rgb(0, 0, 255);">BAIR</span><span style="font-size: medium;">(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(</span><span style="font-size: medium; color: rgb(255, 0, 0);">RL</span><span style="font-size: medium;">)框架。我之前写了一篇它的</span><a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" style="font-size: medium;" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a><span style="font-size: medium;">。&#160;</span><br style="font-size: medium;" /><br />
	<span style="font-size: medium;">rlpyt 可利用GPU来训练模型，理论上速度会比CPU快。</span></p>
</section>
</section>
</section>
</section>
<p><span id="more-11914"></span></p>
<p><span style="color:#ff0000;">✔</span> 安装GPU版的PyTorch<br />
在Anaconda下，利用rlpyt自带的&#160;<span style="color:#b22222;">linux_cuda10.yml</span> 或&#160;<span style="color:#b22222;">linux_cuda9.yml</span> 来安装 rlpyt 依赖的Anaconda env（取决于你使用的CUDA Version是多少）。<br />
使用 <span style="color:#0000ff;">nvidia-smi</span> 命令查看 CUDA Version：</p>
<blockquote>
<div>
		NVIDIA-SMI 410.72&#160; &#160; &#160; &#160;Driver Version: 410.72&#160; &#160; &#160; &#160;CUDA Version: 10.0</div>
</blockquote>
<div>
	我的是 10.0，因此修改&#160;<span style="color: rgb(178, 34, 34);">linux_cuda10.yml</span></div>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e4%bd%bf%e7%94%a8gpu%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p></p>
<section class="RankEditor" data-opacity="1" data-rotate="0" data-width="100%" style="width: 100%; margin: 0px auto; opacity: 1;transform: rotateZ(0deg);-webkit-transform: rotateZ(0deg);-moz-transform: rotateZ(0deg);-ms-transform: rotateZ(0deg);-o-transform: rotateZ(0deg);">
<section style="margin-right: auto; margin-left: auto; display: flex; justify-content: center; align-items: center;">
<section style="width: 100%; border-radius: 5px; border: 1px solid rgb(105, 105, 105); padding: 6px; box-sizing: border-box;">
<section style="width: 100%; border-radius: 5px; border: 1px solid rgb(255, 185, 15); padding: 20px; text-align: justify; box-sizing: border-box;">
<p class="brush active" style=" font-size: 13px; color: rgb(51, 51, 51); letter-spacing: 1.5px; line-height: 1.75;min-width:1px;">
	<a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" style="font-size: medium;" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a><span style="font-size: medium;">&nbsp;是</span><span style="font-size: medium; color: rgb(0, 0, 255);">BAIR</span><span style="font-size: medium;">(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(</span><span style="font-size: medium; color: rgb(255, 0, 0);">RL</span><span style="font-size: medium;">)框架。我之前写了一篇它的</span><a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" style="font-size: medium;" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a><span style="font-size: medium;">。&nbsp;</span><br style="font-size: medium;" /><br />
	<span style="font-size: medium;">rlpyt 可利用GPU来训练模型，理论上速度会比CPU快。</span></p>
</section>
</section>
</section>
</section>
<p><span id="more-11914"></span></p>
<p><span style="color:#ff0000;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 安装GPU版的PyTorch<br />
在Anaconda下，利用rlpyt自带的&nbsp;<span style="color:#b22222;">linux_cuda10.yml</span> 或&nbsp;<span style="color:#b22222;">linux_cuda9.yml</span> 来安装 rlpyt 依赖的Anaconda env（取决于你使用的CUDA Version是多少）。<br />
使用 <span style="color:#0000ff;">nvidia-smi</span> 命令查看 CUDA Version：</p>
<blockquote>
<div>
		NVIDIA-SMI 410.72&nbsp; &nbsp; &nbsp; &nbsp;Driver Version: 410.72&nbsp; &nbsp; &nbsp; &nbsp;CUDA Version: 10.0</div>
</blockquote>
<div>
	我的是 10.0，因此修改&nbsp;<span style="color: rgb(178, 34, 34);">linux_cuda10.yml</span>，把下面这行：</div>
<blockquote>
<div>
		cudatoolkit=10.</div>
</blockquote>
<div>
	改成：</div>
<blockquote>
<div>
		cudatoolkit=10.0</div>
</blockquote>
<div>
	我测试下来，如果不改，rlpyt env也可以安装成功，但是装上的是CPU版的PyTorch；不仅如此，如果你服务器上的CUDA Version是10.1的，你也要把 yml 配置文件里改成 10.0，否则装上的也是CPU版的PyTorch：</p>
<blockquote>
<div>
			~$ conda list | grep pytorch</div>
<div>
			_pytorch_select&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0.1&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cpu_0&nbsp; &nbsp; defaults</div>
<div>
			pytorch&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1.2.0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cpu_py37h00be3c6_0&nbsp; &nbsp; defaults</div>
</blockquote>
<p>	<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
	改了之后装上的就是GPU版的PyTorch了：</p>
<blockquote>
<div>
			~$ conda list | grep pytorch</div>
<div>
			_pytorch_select&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;0.2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;gpu_0&nbsp; &nbsp; defaults</div>
<div>
			pytorch&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;1.2.0&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;cuda100py37h938c94c_0&nbsp; &nbsp; defaults</div>
</blockquote>
<div>
		<br />
		<span style="color: rgb(255, 0, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;在模型训练程序调度GPU<br />
		具体应该怎么写GPU相关的程序，取决于你要实现什么样的功能。例如，使用同步/异步模式，它们对应的Sampler是不同的，等等。<br />
		涉及到具体的代码，这里难以给出一个详细的说明，可以参考 rlpyt 的examples代码。<br />
		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
		<span style="color: rgb(255, 0, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;确认真的在使用GPU训练<br />
		依然使用&nbsp;<span style="color: rgb(0, 0, 255);">nvidia-smi</span>&nbsp;命令来检测，正常情况下，在模型开始训练后，会看到 Processes 列表中有你的模型训练进程：</div>
<blockquote>
<div>
			3&nbsp; &nbsp; &nbsp;17754&nbsp; &nbsp; &nbsp; C&nbsp; &nbsp;.../.anaconda/envs/rlpyt/bin/python&nbsp; &nbsp;459MiB</div>
</blockquote>
<div>
		此外，在模型训练的过程中，查看GPU使用率应该不为0：</div>
<blockquote>
<div>
			dstat --nvidia-gpu -af</div>
</blockquote>
<div>
		这样就OK了。<br />
		据我实测，在我的应用场景中，同样功能的强化学习程序，GPU版比CPU版的模型训练速度快50%左右，GPU单卡使用率最高约为14%（只使用了一张卡，Nvidia P40显卡）。<br />
		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
		<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
		转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
		感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
			<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
</p></div>
</div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e4%bd%bf%e7%94%a8gpu%e8%ae%ad%e7%bb%83%e6%a8%a1%e5%9e%8b/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 强化学习框架 rlpyt 的 size mismatch 错误原因及解决办法</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e7%9a%84-size-mismatch-%e9%94%99%e8%af%af%e5%8e%9f%e5%9b%a0%e5%8f%8a%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e7%9a%84-size-mismatch-%e9%94%99%e8%af%af%e5%8e%9f%e5%9b%a0%e5%8f%8a%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Fri, 10 Apr 2020 12:58:06 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[rlpyt]]></category>
		<category><![CDATA[size mismatch]]></category>
		<category><![CDATA[强化学习]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=11890</guid>

					<description><![CDATA[<p>
查看关于 rlpyt&#160;的更多文章请点击<a href="https://www.codelast.com/?p=10907" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a>&#160;是<span style="color: rgb(0, 0, 255);">BAIR</span>(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(<span style="color: rgb(255, 0, 0);">RL</span>)框架。我之前写了一篇它的<a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a>。&#160;<br />
当你使用 rlpyt 来实现自己的强化学习程序时，可能会遇到类似于下面这样的错误：</p>
<blockquote>
<p>
		RuntimeError: size mismatch, m1: [1 x 365], m2: [461 x 32] at /tmp/pip-req-build-_357f2zr/aten/src/TH/generic/THTensorMath.cpp:752</p>
</blockquote>
<p>本文分析错误原因及解决办法。<br />
<span id="more-11890"></span><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);">▶▶</span></span>&#160;错误原因<br />
可能是由于observation space的期望shape与实际shape不匹配造成的。<br />
observation space的期望shape定义在自己写的environment类中，例如：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="python language-python hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">self._observation_space&#160;=&#160;IntBox(
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;low=<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">0</span>,&#160;high=<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">1</span>,
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;shape=<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">461</span>,
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;dtype=<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&#34;int32&#34;</span>)
</code></pre>
</section>
<p>里面的 shape 必须与输入network的特征向量的长度相同。</p>
<p>实际的shape，由自定义的environment类的 get_obs() 函数所决定：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &#34;Helvetica Neue&#34;, Helvetica, &#34;Hiragino Sans GB&#34;, &#34;Microsoft YaHei&#34;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="python language-python hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;"><span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">def</span>&#160;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">get_obs</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(self)</span>&#160;-&#62;&#160;np.ndarray:</span></code></pre>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e7%9a%84-size-mismatch-%e9%94%99%e8%af%af%e5%8e%9f%e5%9b%a0%e5%8f%8a%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/" class="read-more">Read More </a></section>]]></description>
										<content:encoded><![CDATA[<p>
查看关于 rlpyt&nbsp;的更多文章请点击<a href="https://www.codelast.com/?p=10907" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a>&nbsp;是<span style="color: rgb(0, 0, 255);">BAIR</span>(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(<span style="color: rgb(255, 0, 0);">RL</span>)框架。我之前写了一篇它的<a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a>。&nbsp;<br />
当你使用 rlpyt 来实现自己的强化学习程序时，可能会遇到类似于下面这样的错误：</p>
<blockquote>
<p>
		RuntimeError: size mismatch, m1: [1 x 365], m2: [461 x 32] at /tmp/pip-req-build-_357f2zr/aten/src/TH/generic/THTensorMath.cpp:752</p>
</blockquote>
<p>本文分析错误原因及解决办法。<br />
<span id="more-11890"></span><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;错误原因<br />
可能是由于observation space的期望shape与实际shape不匹配造成的。<br />
observation space的期望shape定义在自己写的environment类中，例如：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="python language-python hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;">self._observation_space&nbsp;=&nbsp;IntBox(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;low=<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">0</span>,&nbsp;high=<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">1</span>,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;shape=<span class="hljs-number" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(174, 135, 250); word-wrap: inherit !important; word-break: inherit !important;">461</span>,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;dtype=<span class="hljs-string" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(238, 220, 112); word-wrap: inherit !important; word-break: inherit !important;">&quot;int32&quot;</span>)
</code></pre>
</section>
<p>里面的 shape 必须与输入network的特征向量的长度相同。</p>
<p>实际的shape，由自定义的environment类的 get_obs() 函数所决定：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="python language-python hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;"><span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">def</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">get_obs</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(self)</span>&nbsp;-&gt;&nbsp;np.ndarray:</span>
&nbsp;&nbsp;&nbsp;&nbsp;observation:&nbsp;np.ndarray&nbsp;=&nbsp;xxx&nbsp;&nbsp;<span class="hljs-comment" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(128, 128, 128); word-wrap: inherit !important; word-break: inherit !important;">#&nbsp;此处需要自己实现</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">return</span>&nbsp;observation
</code></pre>
</section>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;解决办法<br />
当出现上面的错误时，以串行模式断点调试上面的程序，在上面两处地方都加上断点，看看期望的shape以及实际的observation shape是不是不相等，如果不相等，就要去调查为什么实际的shape是错的了。解决这个问题以后，上面的问题就迎刃而解。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e7%9a%84-size-mismatch-%e9%94%99%e8%af%af%e5%8e%9f%e5%9b%a0%e5%8f%8a%e8%a7%a3%e5%86%b3%e5%8a%9e%e6%b3%95/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 强化学习框架 rlpyt 源码分析：(10) 基于CPU的并行采样器CpuSampler，worker的实现</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a10-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a10-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Tue, 21 Jan 2020 05:15:53 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[parallelism]]></category>
		<category><![CDATA[Reinforcement Learning]]></category>
		<category><![CDATA[rlpyt]]></category>
		<category><![CDATA[并行]]></category>
		<category><![CDATA[强化学习]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=11674</guid>

					<description><![CDATA[<p>
查看关于 rlpyt&#160;的更多文章请点击<a href="https://www.codelast.com/?p=10907" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a>&#160;是<span style="color: rgb(0, 0, 255);">BAIR</span>(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(<span style="color: rgb(255, 0, 0);">RL</span>)框架。我之前写了一篇它的<a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a>。&#160;本文是<a href="https://www.codelast.com/?p=11613" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">上一篇</span></a>文章的续文，继续分析CpuSampler的源码。<br />
本文将分析 CPU并行模式下的 ParallelSamplerBase 类的worker实现。</p>
<p><span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);">▶▶</span></span>&#160;worker的代码在哪<br />
<span style="color:#0000ff;">rlpyt/samplers/parallel/worker.py</span><br />
<span id="more-11674"></span><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);">▶▶</span></span>&#160;worker是做什么用的<br />
用于采样agent与environment交互得到的数据。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);">▶▶</span></span>&#160;代码分析<br />
我直接在代码里加了大量注释：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#cc7832;">def </span><span style="color:#ffc66d;">initialize_worker</span>(rank<span style="color:#cc7832;">, </span>seed=<span style="color:#cc7832;">None, </span>cpu=<span style="color:#cc7832;">None, </span>torch_threads=<span style="color:#cc7832;">None</span>):
    <span style="color:#629755;font-style:italic;">&#34;&#34;&#34;
</span><span style="color:#629755;font-style:italic;">    </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">初始化采样用的</span><span style="color:#629755;font-style:italic;">worker</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">。
</span>
<span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> rank: </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">采样进程的标识序号。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> seed: </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">种子，一个整数值。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> cpu: CPU</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">序号，例如</span><span style="color:#629755;font-style:italic;"> 0, 1, 2 </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">等等。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> torch_threads: CPU</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">并发执行的线程数。</span>
<span style="color:#629755;font-style:italic;">    &#34;&#34;&#34;
</span><span style="color:#629755;font-style:italic;">    </span>log_str = <span style="color:#6a8759;">f&#34;Sampler rank </span><span style="color:#cc7832;">{</span>rank<span style="color:#cc7832;">}</span><span style="color:#6a8759;"> initialized&#34;
</span><span style="color:#6a8759;">    </span>cpu = [cpu] <span style="color:#cc7832;">if </span><span style="color:#8888c6;">isinstance</span>(cpu<span style="color:#cc7832;">, </span><span style="color:#8888c6;">int</span>) <span style="color:#cc7832;">else </span>cpu
    p = psutil.Process()</pre>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a10-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>
查看关于 rlpyt&nbsp;的更多文章请点击<a href="https://www.codelast.com/?p=10907" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a>&nbsp;是<span style="color: rgb(0, 0, 255);">BAIR</span>(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(<span style="color: rgb(255, 0, 0);">RL</span>)框架。我之前写了一篇它的<a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a>。&nbsp;本文是<a href="https://www.codelast.com/?p=11613" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">上一篇</span></a>文章的续文，继续分析CpuSampler的源码。<br />
本文将分析 CPU并行模式下的 ParallelSamplerBase 类的worker实现。</p>
<p><span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;worker的代码在哪<br />
<span style="color:#0000ff;">rlpyt/samplers/parallel/worker.py</span><br />
<span id="more-11674"></span><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;worker是做什么用的<br />
用于采样agent与environment交互得到的数据。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;代码分析<br />
我直接在代码里加了大量注释：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#cc7832;">def </span><span style="color:#ffc66d;">initialize_worker</span>(rank<span style="color:#cc7832;">, </span>seed=<span style="color:#cc7832;">None, </span>cpu=<span style="color:#cc7832;">None, </span>torch_threads=<span style="color:#cc7832;">None</span>):
    <span style="color:#629755;font-style:italic;">&quot;&quot;&quot;
</span><span style="color:#629755;font-style:italic;">    </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">初始化采样用的</span><span style="color:#629755;font-style:italic;">worker</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">。
</span>
<span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> rank: </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">采样进程的标识序号。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> seed: </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">种子，一个整数值。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> cpu: CPU</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">序号，例如</span><span style="color:#629755;font-style:italic;"> 0, 1, 2 </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">等等。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> torch_threads: CPU</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">并发执行的线程数。</span>
<span style="color:#629755;font-style:italic;">    &quot;&quot;&quot;
</span><span style="color:#629755;font-style:italic;">    </span>log_str = <span style="color:#6a8759;">f&quot;Sampler rank </span><span style="color:#cc7832;">{</span>rank<span style="color:#cc7832;">}</span><span style="color:#6a8759;"> initialized&quot;
</span><span style="color:#6a8759;">    </span>cpu = [cpu] <span style="color:#cc7832;">if </span><span style="color:#8888c6;">isinstance</span>(cpu<span style="color:#cc7832;">, </span><span style="color:#8888c6;">int</span>) <span style="color:#cc7832;">else </span>cpu
    p = psutil.Process()
    <span style="color:#cc7832;">try</span>:
        <span style="color:#cc7832;">if </span>cpu <span style="color:#cc7832;">is not None</span>:
            p.cpu_affinity(cpu)  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">设置</span><span style="color:#808080;">CPU</span><span style="color:#808080;font-family:'AR PL UKai CN';">亲和性</span><span style="color:#808080;">(MacOS</span><span style="color:#808080;font-family:'AR PL UKai CN';">不支持</span><span style="color:#808080;">)
</span><span style="color:#808080;">        </span>cpu_affin = p.cpu_affinity()
    <span style="color:#cc7832;">except </span><span style="color:#8888c6;">AttributeError</span>:
        cpu_affin = <span style="color:#6a8759;">&quot;UNAVAILABLE MacOS&quot;
</span><span style="color:#6a8759;">    </span>log_str += <span style="color:#6a8759;">f&quot;, CPU affinity </span><span style="color:#cc7832;">{</span>cpu_affin<span style="color:#cc7832;">}</span><span style="color:#6a8759;">&quot;
</span><span style="color:#6a8759;">    </span>torch_threads = (<span style="color:#6897bb;">1 </span><span style="color:#cc7832;">if </span>torch_threads <span style="color:#cc7832;">is None and </span>cpu <span style="color:#cc7832;">is not None else
</span><span style="color:#cc7832;">        </span>torch_threads)  <span style="color:#808080;"># Default to 1 to avoid possible MKL hang.
</span><span style="color:#808080;">    </span><span style="color:#cc7832;">if </span>torch_threads <span style="color:#cc7832;">is not None</span>:
        torch.set_num_threads(torch_threads)  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">设置</span><span style="color:#808080;">CPU</span><span style="color:#808080;font-family:'AR PL UKai CN';">并发执行的线程数
</span><span style="color:#808080;font-family:'AR PL UKai CN';">    </span>log_str += <span style="color:#6a8759;">f&quot;, Torch threads </span><span style="color:#cc7832;">{</span>torch.get_num_threads()<span style="color:#cc7832;">}</span><span style="color:#6a8759;">&quot;
</span><span style="color:#6a8759;">    </span><span style="color:#cc7832;">if </span>seed <span style="color:#cc7832;">is not None</span>:
        set_seed(seed)
        time.sleep(<span style="color:#6897bb;">0.3</span>)  <span style="color:#808080;"># (so the printing from set_seed is not intermixed)
</span><span style="color:#808080;">        </span>log_str += <span style="color:#6a8759;">f&quot;, Seed </span><span style="color:#cc7832;">{</span>seed<span style="color:#cc7832;">}</span><span style="color:#6a8759;">&quot;
</span><span style="color:#6a8759;">    </span>logger.log(log_str)


<span style="color:#cc7832;">def </span><span style="color:#ffc66d;">sampling_process</span>(common_kwargs<span style="color:#cc7832;">, </span>worker_kwargs):
    <span style="color:#629755;font-style:italic;">&quot;&quot;&quot;
</span><span style="color:#629755;font-style:italic;">    Arguments fed from the Sampler class in master process.
</span>
<span style="color:#629755;font-style:italic;">    </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">采样进程函数。
</span>
<span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> common_kwargs: </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">各个</span><span style="color:#629755;font-style:italic;">worker</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">通用的参数列表。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> worker_kwargs: </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">各个</span><span style="color:#629755;font-style:italic;">worker</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">可能不同的参数列表。</span>
<span style="color:#629755;font-style:italic;">    &quot;&quot;&quot;
</span><span style="color:#629755;font-style:italic;">    </span>c<span style="color:#cc7832;">, </span>w = AttrDict(**common_kwargs)<span style="color:#cc7832;">, </span>AttrDict(**worker_kwargs)
    initialize_worker(w.rank<span style="color:#cc7832;">, </span>w.seed<span style="color:#cc7832;">, </span>w.cpus<span style="color:#cc7832;">, </span>c.torch_threads)
    <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">初始化用于</span><span style="color:#808080;">training</span><span style="color:#808080;font-family:'AR PL UKai CN';">的</span><span style="color:#808080;">environment</span><span style="color:#808080;font-family:'AR PL UKai CN';">实例和</span><span style="color:#808080;">collector</span><span style="color:#808080;font-family:'AR PL UKai CN';">实例
</span><span style="color:#808080;font-family:'AR PL UKai CN';">    </span>envs = [c.EnvCls(**c.env_kwargs) <span style="color:#cc7832;">for </span>_ <span style="color:#cc7832;">in </span><span style="color:#8888c6;">range</span>(w.n_envs)]
    collector = c.CollectorCls(
        <span style="color:#aa4926;">rank</span>=w.rank<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">envs</span>=envs<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">samples_np</span>=w.samples_np<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">batch_T</span>=c.batch_T<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">TrajInfoCls</span>=c.TrajInfoCls<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">agent</span>=c.get(<span style="color:#6a8759;">&quot;agent&quot;</span><span style="color:#cc7832;">, None</span>)<span style="color:#cc7832;">,  </span><span style="color:#808080;"># Optional depending on parallel setup.
</span><span style="color:#808080;">        </span><span style="color:#aa4926;">sync</span>=w.get(<span style="color:#6a8759;">&quot;sync&quot;</span><span style="color:#cc7832;">, None</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">step_buffer_np</span>=w.get(<span style="color:#6a8759;">&quot;step_buffer_np&quot;</span><span style="color:#cc7832;">, None</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">global_B</span>=c.get(<span style="color:#6a8759;">&quot;global_B&quot;</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">1</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">env_ranks</span>=w.get(<span style="color:#6a8759;">&quot;env_ranks&quot;</span><span style="color:#cc7832;">, None</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">    </span>)
    agent_inputs<span style="color:#cc7832;">, </span>traj_infos = collector.start_envs(c.max_decorrelation_steps)  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">这里会做收集</span><span style="color:#808080;">(</span><span style="color:#808080;font-family:'AR PL UKai CN';">采样</span><span style="color:#808080;">)</span><span style="color:#808080;font-family:'AR PL UKai CN';">第一批数据的工作
</span><span style="color:#808080;font-family:'AR PL UKai CN';">    </span>collector.start_agent()  <span style="color:#808080;"># collector</span><span style="color:#808080;font-family:'AR PL UKai CN';">的初始化
</span>
<span style="color:#808080;font-family:'AR PL UKai CN';">    </span><span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">初始化用于</span><span style="color:#808080;">evaluation</span><span style="color:#808080;font-family:'AR PL UKai CN';">的</span><span style="color:#808080;">environment</span><span style="color:#808080;font-family:'AR PL UKai CN';">实例和</span><span style="color:#808080;">collector</span><span style="color:#808080;font-family:'AR PL UKai CN';">实例
</span><span style="color:#808080;font-family:'AR PL UKai CN';">    </span><span style="color:#cc7832;">if </span>c.get(<span style="color:#6a8759;">&quot;eval_n_envs&quot;</span><span style="color:#cc7832;">, </span><span style="color:#6897bb;">0</span>) &gt; <span style="color:#6897bb;">0</span>:
        eval_envs = [c.EnvCls(**c.eval_env_kwargs) <span style="color:#cc7832;">for </span>_ <span style="color:#cc7832;">in </span><span style="color:#8888c6;">range</span>(c.eval_n_envs)]
        eval_collector = c.eval_CollectorCls(
            <span style="color:#aa4926;">rank</span>=w.rank<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span><span style="color:#aa4926;">envs</span>=eval_envs<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span><span style="color:#aa4926;">TrajInfoCls</span>=c.TrajInfoCls<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span><span style="color:#aa4926;">traj_infos_queue</span>=c.eval_traj_infos_queue<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span><span style="color:#aa4926;">max_T</span>=c.eval_max_T<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span><span style="color:#aa4926;">agent</span>=c.get(<span style="color:#6a8759;">&quot;agent&quot;</span><span style="color:#cc7832;">, None</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span><span style="color:#aa4926;">sync</span>=w.get(<span style="color:#6a8759;">&quot;sync&quot;</span><span style="color:#cc7832;">, None</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span><span style="color:#aa4926;">step_buffer_np</span>=w.get(<span style="color:#6a8759;">&quot;eval_step_buffer_np&quot;</span><span style="color:#cc7832;">, None</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span>)
    <span style="color:#cc7832;">else</span>:
        eval_envs = <span style="color:#8888c6;">list</span>()

    ctrl = c.ctrl  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">用于控制多个</span><span style="color:#808080;">worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">进程同时运行时能正确运作的控制器
</span><span style="color:#808080;font-family:'AR PL UKai CN';">    </span>ctrl.barrier_out.wait()  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">每个</span><span style="color:#808080;">worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">都有一个</span><span style="color:#808080;">wait()</span><span style="color:#808080;font-family:'AR PL UKai CN';">，加上</span><span style="color:#808080;">ParallelSamplerBase.initialize()</span><span style="color:#808080;font-family:'AR PL UKai CN';">中的一个</span><span style="color:#808080;">wait()</span><span style="color:#808080;font-family:'AR PL UKai CN';">，刚好</span><span style="color:#808080;">n_worker+1</span><span style="color:#808080;font-family:'AR PL UKai CN';">个
</span><span style="color:#808080;font-family:'AR PL UKai CN';">    </span><span style="color:#cc7832;">while True</span>:
        collector.reset_if_needed(agent_inputs)  <span style="color:#808080;"># Outside barrier?
</span><span style="color:#808080;">        </span>ctrl.barrier_in.wait()
        <span style="color:#cc7832;">if </span>ctrl.quit.value:  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">在主进程中</span><span style="color:#808080;">set</span><span style="color:#808080;font-family:'AR PL UKai CN';">了这个值为</span><span style="color:#808080;">True</span><span style="color:#808080;font-family:'AR PL UKai CN';">时，所有</span><span style="color:#808080;">worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">进程会退出采样
</span><span style="color:#808080;font-family:'AR PL UKai CN';">            </span><span style="color:#cc7832;">break
</span><span style="color:#cc7832;">        if </span>ctrl.do_eval.value:  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">在主进程的</span><span style="color:#808080;">evaluate_agent()</span><span style="color:#808080;font-family:'AR PL UKai CN';">函数里</span><span style="color:#808080;">set</span><span style="color:#808080;font-family:'AR PL UKai CN';">了这个值为</span><span style="color:#808080;">True</span><span style="color:#808080;font-family:'AR PL UKai CN';">时，这里才会收集</span><span style="color:#808080;">evaluation</span><span style="color:#808080;font-family:'AR PL UKai CN';">用的数据
</span><span style="color:#808080;font-family:'AR PL UKai CN';">            </span>eval_collector.collect_evaluation(ctrl.itr.value)  <span style="color:#808080;"># Traj_infos to queue inside.
</span><span style="color:#808080;">        </span><span style="color:#cc7832;">else</span>:  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">不是做</span><span style="color:#808080;">evaluation
</span><span style="color:#808080;">            </span>agent_inputs<span style="color:#cc7832;">, </span>traj_infos<span style="color:#cc7832;">, </span>completed_infos = collector.collect_batch(
                agent_inputs<span style="color:#cc7832;">, </span>traj_infos<span style="color:#cc7832;">, </span>ctrl.itr.value)
            <span style="color:#cc7832;">for </span>info <span style="color:#cc7832;">in </span>completed_infos:
                c.traj_infos_queue.put(info)  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">向所有</span><span style="color:#808080;">worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">进程共享的队列塞入当前</span><span style="color:#808080;">worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">的统计数据
</span><span style="color:#808080;font-family:'AR PL UKai CN';">        </span>ctrl.barrier_out.wait()

    <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">清理</span><span style="color:#808080;">environment
</span><span style="color:#808080;">    </span><span style="color:#cc7832;">for </span>env <span style="color:#cc7832;">in </span>envs + eval_envs:
        env.close()
</pre>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
在worker的代码中，比较绕的就是，worker是怎么把采样到的数据返回放到replay buffer里的？<br />
在<a href="https://www.codelast.com/?p=11613" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">上一篇</span></a>文章中，我们知道 ParallelSamplerBase.initialize() 函数初始化了replay buffer：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
examples = <span style="color:#94558d;">self</span>._build_buffers(env<span style="color:#cc7832;">, </span>bootstrap_value)</pre>
<p>以及：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#cc7832;">def </span><span style="color:#ffc66d;">_build_buffers</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>env<span style="color:#cc7832;">, </span>bootstrap_value):
    <span style="color:#94558d;">self</span>.samples_pyt<span style="color:#cc7832;">, </span><span style="color:#94558d;">self</span>.samples_np<span style="color:#cc7832;">, </span>examples = build_samples_buffer(
        <span style="color:#94558d;">self</span>.agent<span style="color:#cc7832;">, </span>env<span style="color:#cc7832;">, </span><span style="color:#94558d;">self</span>.batch_spec<span style="color:#cc7832;">, </span>bootstrap_value<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">agent_shared</span>=<span style="color:#cc7832;">True, </span><span style="color:#aa4926;">env_shared</span>=<span style="color:#cc7832;">True, </span><span style="color:#aa4926;">subprocess</span>=<span style="color:#cc7832;">True</span>)
    <span style="color:#cc7832;">return </span>examples</pre>
<p>在这里，self.samples_np 对应的是replay buffer的存储对象。而 worker 的参数&nbsp;workers_kwargs 初始化的时候，会把 self.samples_np 拆分成多个slice，并传入 worker：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#aa4926;">samples_np</span>=<span style="color:#94558d;">self</span>.samples_np[:<span style="color:#cc7832;">, </span>slice_B]<span style="color:#cc7832;">,</span></pre>
<p>在 worker 中，构造 collector 对象的时候，会把这个传入的 samples_np 再传给 collector 的构造函数。这样，replay buffer 就与 collector 关联起来了。<br />
最后，在 collector.collect_batch() 的时候，会把采样得到的数据放入 samples_np 中，也就是相当于放到了 replay buffer 里。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
这一节就到这，且听下回分解。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a10-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 强化学习框架 rlpyt 源码分析：(9) 基于CPU的并行采样器CpuSampler</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a9-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a9-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Mon, 20 Jan 2020 09:16:20 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[parallelism]]></category>
		<category><![CDATA[Reinforcement Learning]]></category>
		<category><![CDATA[rlpyt]]></category>
		<category><![CDATA[并行]]></category>
		<category><![CDATA[强化学习]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=11613</guid>

					<description><![CDATA[<p>
查看关于 rlpyt&#160;的更多文章请点击<a href="https://www.codelast.com/?p=10907" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a>&#160;是<span style="color: rgb(0, 0, 255);">BAIR</span>(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(<span style="color: rgb(255, 0, 0);">RL</span>)框架。我之前写了一篇它的<a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a>。&#160;本文是<a href="https://www.codelast.com/?p=11441" rel="noopener noreferrer" target="_blank"><span style="background-color:#ffa07a;">上一篇</span></a>文章的续文，继续分析CpuSampler的源码。<br />
我们已经知道了CpuSampler有两个父类：BaseSampler&#160;和&#160;ParallelSamplerBase。其中，BaseSampler主要是定义了一堆接口，没什么好说的，因此本文接着分析另一个父类&#160;ParallelSamplerBase。在&#160;ParallelSamplerBase 中，初始化函数&#160;initialize() 做了很多重要的工作，已经够写一篇长长的文章来分析了，这正是本文的主要内容。<br />
<span id="more-11613"></span><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);">▶▶</span></span>&#160;初始化函数 initialize()&#160;做了哪些重要工作<br />
一句话总结 initialize() 的重要功能：计算一些特殊参数的值，初始化agent，创建<span style="color:#0000ff;">并行控制器</span>，创建并启动多个worker进程。<br />
<span style="color:#ff0000;">✍</span> 这里说的&#8220;<span style="color: rgb(0, 0, 255);">并行控制器</span>&#8221;(parallel ctrl)是指用Python&#160;multiprocessing模块来实现并行功能的时候，需要使用一些变量来协调各个并行的进程，使它们可以正确运作。这些用于协调的变量就是&#8220;并行控制器&#8221;。</p>
<p><span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);">▶▶</span></span>&#160;计算特殊参数的值<br />
在并行模式下，有些参数（比如采样用的worker的数量）不是由用户直接设置的，而是计算出来的。而且这样的参数还挺多，所以有大段大段的代码都用来干这事了。<br />
如果下面的代码没有注释的话，肯定会让人一头雾水：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
n_envs_list = <span style="color:#94558d;">self</span>._get_n_envs_list(</pre>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a9-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>
查看关于 rlpyt&nbsp;的更多文章请点击<a href="https://www.codelast.com/?p=10907" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a>&nbsp;是<span style="color: rgb(0, 0, 255);">BAIR</span>(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(<span style="color: rgb(255, 0, 0);">RL</span>)框架。我之前写了一篇它的<a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a>。&nbsp;本文是<a href="https://www.codelast.com/?p=11441" rel="noopener noreferrer" target="_blank"><span style="background-color:#ffa07a;">上一篇</span></a>文章的续文，继续分析CpuSampler的源码。<br />
我们已经知道了CpuSampler有两个父类：BaseSampler&nbsp;和&nbsp;ParallelSamplerBase。其中，BaseSampler主要是定义了一堆接口，没什么好说的，因此本文接着分析另一个父类&nbsp;ParallelSamplerBase。在&nbsp;ParallelSamplerBase 中，初始化函数&nbsp;initialize() 做了很多重要的工作，已经够写一篇长长的文章来分析了，这正是本文的主要内容。<br />
<span id="more-11613"></span><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;初始化函数 initialize()&nbsp;做了哪些重要工作<br />
一句话总结 initialize() 的重要功能：计算一些特殊参数的值，初始化agent，创建<span style="color:#0000ff;">并行控制器</span>，创建并启动多个worker进程。<br />
<span style="color:#ff0000;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270d.png" alt="✍" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 这里说的&ldquo;<span style="color: rgb(0, 0, 255);">并行控制器</span>&rdquo;(parallel ctrl)是指用Python&nbsp;multiprocessing模块来实现并行功能的时候，需要使用一些变量来协调各个并行的进程，使它们可以正确运作。这些用于协调的变量就是&ldquo;并行控制器&rdquo;。</p>
<p><span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;计算特殊参数的值<br />
在并行模式下，有些参数（比如采样用的worker的数量）不是由用户直接设置的，而是计算出来的。而且这样的参数还挺多，所以有大段大段的代码都用来干这事了。<br />
如果下面的代码没有注释的话，肯定会让人一头雾水：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
n_envs_list = <span style="color:#94558d;">self</span>._get_n_envs_list(<span style="color:#aa4926;">affinity</span>=affinity)  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">用户设置的</span><span style="color:#808080;">worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">数不一定与</span><span style="color:#808080;">environment</span><span style="color:#808080;font-family:'AR PL UKai CN';">数相匹配，这里会重新调整
</span><span style="color:#94558d;">self</span>.n_worker = n_worker = <span style="color:#8888c6;">len</span>(n_envs_list)  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">经过调整之后的</span><span style="color:#808080;">worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">数
</span>B = <span style="color:#94558d;">self</span>.batch_spec.B  <span style="color:#808080;"># environment</span><span style="color:#808080;font-family:'AR PL UKai CN';">实例的数量
</span>global_B = B * world_size  <span style="color:#808080;"># &quot;</span><span style="color:#808080;font-family:'AR PL UKai CN';">平行宇宙</span><span style="color:#808080;">&quot;</span><span style="color:#808080;font-family:'AR PL UKai CN';">概念下的</span><span style="color:#808080;">environment</span><span style="color:#808080;font-family:'AR PL UKai CN';">实例的数量
</span>env_ranks = <span style="color:#8888c6;">list</span>(<span style="color:#8888c6;">range</span>(rank * B<span style="color:#cc7832;">, </span>(rank + <span style="color:#6897bb;">1</span>) * B))  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">含义可参考：</span><span style="color:#808080;">https://www.codelast.com/?p=10932
</span><span style="color:#94558d;">self</span>.world_size = world_size
<span style="color:#94558d;">self</span>.rank = rank

<span style="color:#cc7832;">if </span><span style="color:#94558d;">self</span>.eval_n_envs &gt; <span style="color:#6897bb;">0</span>:  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">在</span><span style="color:#808080;">example_*.py</span><span style="color:#808080;font-family:'AR PL UKai CN';">中传入的参数
</span><span style="color:#808080;font-family:'AR PL UKai CN';">    </span><span style="color:#94558d;">self</span>.eval_n_envs_per = <span style="color:#8888c6;">max</span>(<span style="color:#6897bb;">1</span><span style="color:#cc7832;">, </span><span style="color:#94558d;">self</span>.eval_n_envs // n_worker)  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">计算每个</span><span style="color:#808080;">worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">至少承载几个</span><span style="color:#808080;">evaluation</span><span style="color:#808080;font-family:'AR PL UKai CN';">的</span><span style="color:#808080;">environment(</span><span style="color:#808080;font-family:'AR PL UKai CN';">至少</span><span style="color:#808080;">1)
</span><span style="color:#808080;">    </span><span style="color:#94558d;">self</span>.eval_n_envs = eval_n_envs = <span style="color:#94558d;">self</span>.eval_n_envs_per * n_worker  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">保证至少有</span><span style="color:#808080;">&quot;worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">数量</span><span style="color:#808080;">&quot;</span><span style="color:#808080;font-family:'AR PL UKai CN';">个</span><span style="color:#808080;">eval environment</span><span style="color:#808080;font-family:'AR PL UKai CN';">实例
</span><span style="color:#808080;font-family:'AR PL UKai CN';">    </span>logger.log(<span style="color:#6a8759;">f&quot;Total parallel evaluation envs: </span><span style="color:#cc7832;">{</span>eval_n_envs<span style="color:#cc7832;">}</span><span style="color:#6a8759;">.&quot;</span>)
    <span style="color:#94558d;">self</span>.eval_max_T = <span style="color:#72737a;">eval_max_T </span>= <span style="color:#8888c6;">int</span>(<span style="color:#94558d;">self</span>.eval_max_steps // eval_n_envs)</pre>
<p>
最为&ldquo;神奇&rdquo;的就是 <span style="color:#0000ff;">self._get_n_envs_list()</span> 这个函数，它用来计算<span style="color:#b22222;">每个worker承载几个environment实例</span>。这个说法是不是特别奇怪？原因是：用户可以指定environment实例的数量，也可以指定worker的数量，但这两个数量可能是不相等的，于是，要么worker数不够，要么worker数有多；在第1种情况下，一个worker需要带&gt;1个environment实例，在第2种情况下，不需要那么多worker，所以要减少worker的数量，才能保证一个worker刚好带一个environment实例。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
我给 self._get_n_envs_list()&nbsp;函数加上了注释，相信足以让大家理解它的功能了：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#cc7832;">def </span><span style="color:#ffc66d;">_get_n_envs_list</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>affinity=<span style="color:#cc7832;">None, </span>n_worker=<span style="color:#cc7832;">None, </span>B=<span style="color:#cc7832;">None</span>):
    <span style="color:#629755;font-style:italic;">&quot;&quot;&quot;
</span><span style="color:#629755;font-style:italic;">    </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">根据</span><span style="color:#629755;font-style:italic;">environment</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">实例的数量</span><span style="color:#629755;font-style:italic;">(</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">所谓的</span><span style="color:#629755;font-style:italic;">&quot;B&quot;)</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">，以及用户设定的用于采样的</span><span style="color:#629755;font-style:italic;">worker</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">的数量</span><span style="color:#629755;font-style:italic;">(n_worker)</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">，来计算得到一个</span><span style="color:#629755;font-style:italic;">list</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">，这个</span><span style="color:#629755;font-style:italic;">list</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">的元素的总数，
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    就是最终的</span><span style="color:#629755;font-style:italic;">worker</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">的数量；而这个</span><span style="color:#629755;font-style:italic;">list</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">里的每个元素的值，分别是每个</span><span style="color:#629755;font-style:italic;">worker</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">承载的</span><span style="color:#629755;font-style:italic;">environment</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">实例的数量。
</span>
<span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> affinity: </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">一个字典</span><span style="color:#629755;font-style:italic;">(dict)</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">，包含硬件亲和性定义。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> n_worker: </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">用户设定的用于采样的</span><span style="color:#629755;font-style:italic;">worker</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">的数量。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> B: environment</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">实例的数量。
</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:return </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">一个</span><span style="color:#629755;font-style:italic;">list</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">，其含义如上所述。</span>
<span style="color:#629755;font-style:italic;">    &quot;&quot;&quot;
</span><span style="color:#629755;font-style:italic;">    </span>B = <span style="color:#94558d;">self</span>.batch_spec.B <span style="color:#cc7832;">if </span>B <span style="color:#cc7832;">is None else </span>B  <span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">参考</span><span style="color:#808080;">BatchSpec</span><span style="color:#808080;font-family:'AR PL UKai CN';">类，可以认为</span><span style="color:#808080;">B</span><span style="color:#808080;font-family:'AR PL UKai CN';">是</span><span style="color:#808080;">environment</span><span style="color:#808080;font-family:'AR PL UKai CN';">实例的数量
</span><span style="color:#808080;font-family:'AR PL UKai CN';">    </span>n_worker = <span style="color:#8888c6;">len</span>(affinity[<span style="color:#6a8759;">&quot;workers_cpus&quot;</span>]) <span style="color:#cc7832;">if </span>n_worker <span style="color:#cc7832;">is None else </span>n_worker  <span style="color:#808080;"># worker</span><span style="color:#808080;font-family:'AR PL UKai CN';">的数量</span><span style="color:#808080;">(</span><span style="color:#808080;font-family:'AR PL UKai CN';">不超过物理</span><span style="color:#808080;">CPU</span><span style="color:#808080;font-family:'AR PL UKai CN';">数否则在别处报错</span><span style="color:#808080;">)
</span><span style="color:#808080;">    </span><span style="color:#6a8759;">&quot;&quot;&quot;
</span><span style="color:#6a8759;">    </span><span style="color:#6a8759;font-family:'AR PL UKai CN';">当</span><span style="color:#6a8759;">environment</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">实例的数量</span><span style="color:#6a8759;">&lt;worker</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">的数量时，例如有</span><span style="color:#6a8759;">8</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">个</span><span style="color:#6a8759;">worker(</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">即</span><span style="color:#6a8759;">8</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">个物理</span><span style="color:#6a8759;">CPU)</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">，</span><span style="color:#6a8759;">5</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">个</span><span style="color:#6a8759;">environment</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">实例，每一个物理</span><span style="color:#6a8759;">CPU</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">运行一个</span><span style="color:#6a8759;">environment</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">，
</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">    那么此时会有</span><span style="color:#6a8759;">3</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">个物理</span><span style="color:#6a8759;">CPU</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">多余，此时就会把</span><span style="color:#6a8759;">worker</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">的数量设置成和</span><span style="color:#6a8759;">environment</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">实例数量一样，使得每个</span><span style="color:#6a8759;">CPU</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">都刚好运行一个</span><span style="color:#6a8759;">environment</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">实例。</span>
<span style="color:#6a8759;">    &quot;&quot;&quot;
</span><span style="color:#6a8759;">    </span><span style="color:#cc7832;">if </span>B &lt; n_worker:
        logger.log(<span style="color:#6a8759;">f&quot;WARNING: requested fewer envs (</span><span style="color:#cc7832;">{</span>B<span style="color:#cc7832;">}</span><span style="color:#6a8759;">) than available worker &quot;
</span><span style="color:#6a8759;">            f&quot;processes (</span><span style="color:#cc7832;">{</span>n_worker<span style="color:#cc7832;">}</span><span style="color:#6a8759;">). Using fewer workers (but maybe better to &quot;
</span><span style="color:#6a8759;">            &quot;increase sampler&#39;s `batch_B`.&quot;</span>)
        n_worker = B
    n_envs_list = [B // n_worker] * n_worker
    <span style="color:#6a8759;">&quot;&quot;&quot;
</span><span style="color:#6a8759;">    </span><span style="color:#6a8759;font-family:'AR PL UKai CN';">当</span><span style="color:#6a8759;">environment</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">实例的数量不是</span><span style="color:#6a8759;">worker</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">数量的整数倍时，每个</span><span style="color:#6a8759;">worker</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">被分配到的</span><span style="color:#6a8759;">environment</span><span style="color:#6a8759;font-family:'AR PL UKai CN';">实例的数量是不均等的。</span>
<span style="color:#6a8759;">    &quot;&quot;&quot;
</span><span style="color:#6a8759;">    </span><span style="color:#cc7832;">if not </span>B % n_worker == <span style="color:#6897bb;">0</span>:
        logger.log(<span style="color:#6a8759;">&quot;WARNING: unequal number of envs per process, from &quot;
</span><span style="color:#6a8759;">            f&quot;batch_B </span><span style="color:#cc7832;">{</span><span style="color:#94558d;">self</span>.batch_spec.B<span style="color:#cc7832;">}</span><span style="color:#6a8759;"> and n_worker </span><span style="color:#cc7832;">{</span>n_worker<span style="color:#cc7832;">} </span><span style="color:#6a8759;">&quot;
</span><span style="color:#6a8759;">            &quot;(possible suboptimal speed).&quot;</span>)
        <span style="color:#cc7832;">for </span>b <span style="color:#cc7832;">in </span><span style="color:#8888c6;">range</span>(B % n_worker):
            n_envs_list[b] += <span style="color:#6897bb;">1
</span><span style="color:#6897bb;">    </span><span style="color:#cc7832;">return </span>n_envs_list</pre>
<p><span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;初始化agent<br />
<span style="color:#0000ff;">agent对象只有一个</span>！并不是每一个worker进程都对应到不同的agent对象！这是理解CpuSampler时需要知晓的一个重要概念。<br />
agent通过以下代码初始化（ParallelSamplerBase.initialize() 函数）：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Menlo';font-size:12.0pt;">
env = <span style="color:#94558d;">self</span>.<span style="color:#cc7833;">EnvCls</span>(**<span style="color:#94558d;">self</span>.env_kwargs)
<span style="color:#94558d;">self</span>.<span style="color:#cc7833;">_agent_init</span>(agent<span style="color:#cc7832;">, </span>env<span style="color:#cc7832;">, </span><span style="color:#aa4926;">global_B</span>=global_B<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">    </span><span style="color:#aa4926;">env_ranks</span>=env_ranks)
examples = <span style="color:#94558d;">self</span>.<span style="color:#cc7833;">_build_buffers</span>(env<span style="color:#cc7832;">, </span>bootstrap_value)
env.<span style="color:#cc7833;">close</span>()
<span style="color:#cc7832;font-weight:bold;">del </span>env</pre>
<p>可以看到，这里初始化了environment对象，并把它作为一个参数传给了agent初始化函数 self._agent_init()，事实上，在&nbsp;self._agent_init()&nbsp;函数里，只用到了 env&nbsp;对象的 <span style="color:#0000ff;">spaces</span>&nbsp;这个属性，而没有引用整个 env 对象，因此在使用完之后，使用 env.close()&nbsp;以及 del env&nbsp;来清理掉env不会有问题。<br />
self._build_buffers() 是一个非常复杂的操作，它的主要功能是创建强化学习中必备的<span style="color:#0000ff;">replay buffer</span>。直觉上，有人可能认为replay buffer这个东西，不就是创建一个list或者类似的数据结构就能搞定的吗？但实际上不是这么简单，从这个函数一级级点进去就会发现代码还不少，而且它里面甚至还用到了Python&nbsp;multiprocessing，所以创建replay buffer的实现就不在本文分析了。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
self._agent_init()&nbsp;函数的实现很简单：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Menlo';font-size:12.0pt;">
<span style="color:#cc7832;font-weight:bold;">def </span><span style="font-weight:bold;">_agent_init</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>agent<span style="color:#cc7832;">, </span>env<span style="color:#cc7832;">, </span>global_B=<span style="color:#6897bb;">1</span><span style="color:#cc7832;">, </span>env_ranks=<span style="color:#cc7832;font-weight:bold;">None</span>):
    agent.<span style="color:#cc7833;">initialize</span>(env.spaces<span style="color:#cc7832;">, </span><span style="color:#aa4926;">share_memory</span>=<span style="color:#cc7832;font-weight:bold;">True</span><span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">global_B</span>=global_B<span style="color:#cc7832;">, </span><span style="color:#aa4926;">env_ranks</span>=env_ranks)
    <span style="color:#94558d;">self</span>.agent = agent</pre>
<p>在这里看到：agent初始化之后，赋值给了 self.agent，这就是&nbsp;CpuSampler&nbsp;中唯一使用的 agent&nbsp;对象。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;创建并行控制器<br />
并行控制器(parallel ctrl)用于协调多个采样用的worker进程。<br />
在&nbsp;initialize() 里，创建并行控制器的代码只有一句：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#cc7832;">def </span><span style="color:#ffc66d;">_build_parallel_ctrl</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>n_worker):
    <span style="color:#629755;font-style:italic;">&quot;&quot;&quot;
</span><span style="color:#629755;font-style:italic;">    </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">创建用于控制并行训练过程的一些数据结构。</span>

<span style="color:#629755;font-style:italic;">    multiprocessing.RawValue</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">：不存在</span><span style="color:#629755;font-style:italic;">lock</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">的多进程间共享值。</span>
<span style="color:#629755;font-style:italic;">    multiprocessing.Barrier</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">：一种简单的同步原语，用于固定数目的进程相互等待。当所有进程都调用</span><span style="color:#629755;font-style:italic;">wait</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">以后，所有进程会同时开始执行。</span>
<span style="color:#629755;font-style:italic;">    multiprocessing.Queue</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">：用于多进程间数据传递的消息队列。
</span>
<span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">    </span><span style="color:#629755;font-weight:bold;font-style:italic;">:param</span><span style="color:#629755;font-style:italic;"> n_worker: </span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">真正的</span><span style="color:#629755;font-style:italic;">worker</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">数</span><span style="color:#629755;font-style:italic;">(</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">不一定等于用户设置的那个原始值</span><span style="color:#629755;font-style:italic;">)</span><span style="color:#629755;font-style:italic;font-family:'AR PL UKai CN';">。</span>
<span style="color:#629755;font-style:italic;">    &quot;&quot;&quot;
</span><span style="color:#629755;font-style:italic;">    </span><span style="color:#94558d;">self</span>.ctrl = AttrDict(
        <span style="color:#aa4926;">quit</span>=mp.RawValue(ctypes.c_bool<span style="color:#cc7832;">, False</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">barrier_in</span>=mp.Barrier(n_worker + <span style="color:#6897bb;">1</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">barrier_out</span>=mp.Barrier(n_worker + <span style="color:#6897bb;">1</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">do_eval</span>=mp.RawValue(ctypes.c_bool<span style="color:#cc7832;">, False</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span><span style="color:#aa4926;">itr</span>=mp.RawValue(ctypes.c_long<span style="color:#cc7832;">, </span><span style="color:#6897bb;">0</span>)<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">    </span>)
    <span style="color:#94558d;">self</span>.traj_infos_queue = mp.Queue()
    <span style="color:#94558d;">self</span>.eval_traj_infos_queue = mp.Queue()
    <span style="color:#94558d;">self</span>.sync = AttrDict(<span style="color:#aa4926;">stop_eval</span>=mp.RawValue(ctypes.c_bool<span style="color:#cc7832;">, False</span>))</pre>
<p>这里AttrDict是一个&ldquo;扩展的&rdquo;dict，mp就是Python&nbsp;multiprocessing模块，而Python&nbsp;multiprocessing是一个巨大的话题，我自己也只是初步了解，所以没办法讲透彻，这里只举两个例子，来说明这些并行控制器的作用：<br />
<span style="color:#0000ff;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;ctrl.quit 可以理解为一个bool类型的进程间共享变量。在 minibatch_rl.py 中，训练完成后，会执行 shutdown()，它会调用 sampler.shutdown()，从而会把 ctrl.quit 的值设置为True；同时，在 worker.py 中会看到，当检测到 ctrl.quit 的值为True时，会退出采样过程。所有采样的worker进程都受这个变量控制。所以这样就做到了在主进程中控制并行跑的worker进程。<br />
<span style="color:#0000ff;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;multiprocessing.Queue() 用于在多进程间传递消息。在每个采样的worker进程中，会把收集到的trajectory info放到同一个traj_infos_queue中，在主进程中会把汇总的trajectory info进一步处理成统计数据，然后记日志、打印到屏幕上，等等。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;创建并启动多个worker进程<br />
worker进程用于采样(agent与environment交互得到的)数据。<br />
在创建这些进程之前，需要先为它们构建所需的参数：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
common_kwargs = <span style="color:#94558d;">self</span>._assemble_common_kwargs(affinity<span style="color:#cc7832;">, </span>global_B)
workers_kwargs = <span style="color:#94558d;">self</span>._assemble_workers_kwargs(affinity<span style="color:#cc7832;">, </span>seed<span style="color:#cc7832;">, </span>n_envs_list)</pre>
<p>为什么需要分成&nbsp;<span style="color:#0000ff;">common_kwargs</span> 以及&nbsp;<span style="color:#0000ff;">workers_kwargs</span> 两个参数？这是因为：对每个worker进程来说，有些参数是通用的，有些参数是不通用的（例如，每个worker使用的CPU数量、承载的environment实例的数量等），因此，rlpyt把它们分成了两拨，分别放在两个对象里。</p>
<p>在准备好了参数之后，就开始创建多个worker进程，并把它们启动起来了：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">创建一批子进程
</span>target = sampling_process <span style="color:#cc7832;">if </span>worker_process <span style="color:#cc7832;">is None else </span>worker_process
<span style="color:#94558d;">self</span>.workers = [mp.Process(<span style="color:#aa4926;">target</span>=target<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">    </span><span style="color:#aa4926;">kwargs</span>=<span style="color:#8888c6;">dict</span>(<span style="color:#aa4926;">common_kwargs</span>=common_kwargs<span style="color:#cc7832;">, </span><span style="color:#aa4926;">worker_kwargs</span>=w_kwargs))
    <span style="color:#cc7832;">for </span>w_kwargs <span style="color:#cc7832;">in </span>workers_kwargs]
<span style="color:#808080;"># </span><span style="color:#808080;font-family:'AR PL UKai CN';">启动子进程
</span><span style="color:#cc7832;">for </span>w <span style="color:#cc7832;">in </span><span style="color:#94558d;">self</span>.workers:
    w.start()

<span style="color:#94558d;">self</span>.ctrl.barrier_out.wait()  <span style="color:#808080;"># Wait for workers ready (e.g. decorrelate).</span></pre>
<p>在这里，使用的是 multiprocessing.Process() 来创建的进程，target 为进程函数名，进程函数是可以自行指定的，rlpyt也提供了默认的实现，即 worker.py 中的&nbsp;sampling_process() 函数。采样进程的实现代码 worker.py 虽然不长，但要完全看懂并不容易，所以留到后面的文章再分析。<br />
在worker进程启动之后，它就进入了持续的采样过程。注意上面代码的最后一句&nbsp;<span style="color:#0000ff;">self.ctrl.barrier_out.wait()</span>，这里使用了 multiprocessing的Barrier来控制各个worker进程同步。由于 barrier_out 创建的时候是这样的：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono';font-size:13.5pt;">
<span style="color:#aa4926;">barrier_out</span>=mp.Barrier(n_worker + <span style="color:#6897bb;">1</span>)</pre>
<p>所以，它需要 <span style="color:#0000ff;">n_worker + 1 </span>个 wait() 才能让所有进程同时&ldquo;解锁&rdquo;（即同时开始执行），在 initialize() 函数里的&nbsp;<span style="color: rgb(0, 0, 255);">self.ctrl.barrier_out.wait()&nbsp;</span>算一个，每个worker函数&mdash;&mdash;即 sampling_process()&mdash;&mdash;里也分别有一个 barrier_out.wait()，所有这些 wait() 加起来刚好是 <span style="color:#0000ff;">n_worker + 1</span> 个，这使得 initialize() 函数执行完，所有 worker 就会&ldquo;跑起来&rdquo;开始采样。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
这一节就到这，且听下回分解。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a9-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>[原创] 强化学习框架 rlpyt 源码分析：(8) 基于CPU的并行采样器CpuSampler</title>
		<link>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a8-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/</link>
					<comments>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a8-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/#respond</comments>
		
		<dc:creator><![CDATA[learnhard]]></dc:creator>
		<pubDate>Sun, 12 Jan 2020 09:40:26 +0000</pubDate>
				<category><![CDATA[Algorithm]]></category>
		<category><![CDATA[原创]]></category>
		<category><![CDATA[parallelism]]></category>
		<category><![CDATA[Reinforcement Learning]]></category>
		<category><![CDATA[rlpyt]]></category>
		<category><![CDATA[并行]]></category>
		<category><![CDATA[强化学习]]></category>
		<guid isPermaLink="false">https://www.codelast.com/?p=11441</guid>

					<description><![CDATA[<p>
<em>写这篇文章的过程中，我改稿改到怀疑人生，因为有些我自己下的结论在看了很多次源码之后又自我否定了多次，所以这篇文章花了我很长时间才完工。虽然完稿之后我仍然不敢保证绝对正确，但这至少是在我当前认知情况下我&#8220;自以为&#8221;正确的版本了，写长稿不易，望理解。</em></p>
<p>查看关于 rlpyt&#160;的更多文章请点击<a href="https://www.codelast.com/?p=10907" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a>&#160;是<span style="color: rgb(0, 0, 255);">BAIR</span>(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(<span style="color: rgb(255, 0, 0);">RL</span>)框架。我之前写了一篇它的<a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a>。&#160;</p>
<p>在单机上支持丰富的并行(Parallelism)模式是 rlpyt 有别于很多其他强化学习框架的一个显著特征。rlpyt可以使用纯CPU，或CPU、GPU混合的方式来并行执行训练过程。<br />
<span id="more-11441"></span><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);">▶▶</span></span>&#160;rlpyt的sampler模块概览<br />
rlpyt有一种叫做&#8220;<a href="https://www.codelast.com/?p=10750" rel="noopener noreferrer" target="_blank"><span style="background-color:#ffa07a;">Sampler</span></a>&#8221;的模块，我们姑且称之为&#8220;采样器&#8221;，它用于采样/收集agent与environment交互的数据，对于不同的训练模式(串行、并行、异步)，rlpyt有不同的sampler实现：</p>
<blockquote>
<div>
		├── <span style="color:#0000ff;">async_</span></div>
<div>
		│&#160; &#160;├── action_server.py</div>
<div>
		│&#160; &#160;├── alternating_sampler.py</div>
<div>
		│&#160; &#160;├── base.py</div>
<div>
		│&#160; &#160;├── collectors.py</div>
<div>
		│&#160; &#160;├── cpu_sampler.py</div></blockquote>&#8230; <a href="https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a8-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/" class="read-more">Read More </a>]]></description>
										<content:encoded><![CDATA[<p>
<em>写这篇文章的过程中，我改稿改到怀疑人生，因为有些我自己下的结论在看了很多次源码之后又自我否定了多次，所以这篇文章花了我很长时间才完工。虽然完稿之后我仍然不敢保证绝对正确，但这至少是在我当前认知情况下我&ldquo;自以为&rdquo;正确的版本了，写长稿不易，望理解。</em></p>
<p>查看关于 rlpyt&nbsp;的更多文章请点击<a href="https://www.codelast.com/?p=10907" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">这里</span></a>。</p>
<p><a href="https://github.com/astooke/rlpyt" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">rlpyt</span></a>&nbsp;是<span style="color: rgb(0, 0, 255);">BAIR</span>(Berkeley Artificial Intelligence Research，伯克利人工智能研究所)开源的一个强化学习(<span style="color: rgb(255, 0, 0);">RL</span>)框架。我之前写了一篇它的<a href="https://www.codelast.com/?p=10643" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">简介</span></a>。&nbsp;</p>
<p>在单机上支持丰富的并行(Parallelism)模式是 rlpyt 有别于很多其他强化学习框架的一个显著特征。rlpyt可以使用纯CPU，或CPU、GPU混合的方式来并行执行训练过程。<br />
<span id="more-11441"></span><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;rlpyt的sampler模块概览<br />
rlpyt有一种叫做&ldquo;<a href="https://www.codelast.com/?p=10750" rel="noopener noreferrer" target="_blank"><span style="background-color:#ffa07a;">Sampler</span></a>&rdquo;的模块，我们姑且称之为&ldquo;采样器&rdquo;，它用于采样/收集agent与environment交互的数据，对于不同的训练模式(串行、并行、异步)，rlpyt有不同的sampler实现：</p>
<blockquote>
<div>
		├── <span style="color:#0000ff;">async_</span></div>
<div>
		│&nbsp; &nbsp;├── action_server.py</div>
<div>
		│&nbsp; &nbsp;├── alternating_sampler.py</div>
<div>
		│&nbsp; &nbsp;├── base.py</div>
<div>
		│&nbsp; &nbsp;├── collectors.py</div>
<div>
		│&nbsp; &nbsp;├── cpu_sampler.py</div>
<div>
		│&nbsp; &nbsp;├── gpu_sampler.py</div>
<div>
		│&nbsp; &nbsp;└── serial_sampler.py</div>
<div>
		├── base.py</div>
<div>
		├── buffer.py</div>
<div>
		├── collections.py</div>
<div>
		├── collectors.py</div>
<div>
		├── <span style="color:#0000ff;">parallel</span></div>
<div>
		│&nbsp; &nbsp;├── base.py</div>
<div>
		│&nbsp; &nbsp;├── cpu</div>
<div>
		│&nbsp; &nbsp;│&nbsp; &nbsp;├── collectors.py</div>
<div>
		│&nbsp; &nbsp;│&nbsp; &nbsp;└── sampler.py</div>
<div>
		│&nbsp; &nbsp;├── gpu</div>
<div>
		│&nbsp; &nbsp;│&nbsp; &nbsp;├── action_server.py</div>
<div>
		│&nbsp; &nbsp;│&nbsp; &nbsp;├── alternating_sampler.py</div>
<div>
		│&nbsp; &nbsp;│&nbsp; &nbsp;├── collectors.py</div>
<div>
		│&nbsp; &nbsp;│&nbsp; &nbsp;└── sampler.py</div>
<div>
		│&nbsp; &nbsp;└── worker.py</div>
<div>
		├── <span style="color:#0000ff;">serial</span></div>
<div>
		│&nbsp; &nbsp;├── collectors.py</div>
<div>
		│&nbsp; &nbsp;└── sampler.py</div>
</blockquote>
<p>
直观感受：串行(<span style="color:#0000ff;">serial</span>)模式的sampler代码最简单，并行(<span style="color:#0000ff;">parallel</span>)模式下的cpu并行实现比gpu并行实现简单一些，异步(<span style="color:#0000ff;">async_</span>)模式下的实现最复杂。<br />
不知道会不会有人好奇：为什么异步模式的module名是带下划线的<span style="color:#0000ff;">async_</span>而不是async呢？因为async在Python 3里是一个关键字，rlpyt的作者应该是为了避开这个问题才加了一个下划线。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
在前面的系列源码分析文章中，我已经分析过了串行(<span style="color: rgb(0, 0, 255);">serial</span>)模式下的sampler代码，本文想分析的是并行(<span style="color: rgb(0, 0, 255);">parallel</span>)模式下的CPU并行实现代码，也就是树形图里的这一部分：</p>
<div>
<blockquote>
<div>
			├── cpu</div>
<div>
			│&nbsp; &nbsp;├── collectors.py</div>
<div>
			│&nbsp; &nbsp;└── sampler.py</div>
</blockquote>
<div>
		CPU sampler在采样/收集数据的时候，完全不使用GPU，因此相对于GPU sampler来说会简单得多（只是相对而言）。它只有两个代码文件。当然，由于这两个文件里的class会继承其他父类，因此最终有关联的代码文件远不止这两个。下面我们就来详细分析一下。<br />
		<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
		<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;CPU sampler概览<br />
		CPU sampler的实现类是&nbsp;CpuSampler，一级级向上，有多个父类：</div>
</div>
<p><img decoding="async" alt="rlpyt" src="https://www.codelast.com/wp-content/uploads/2020/01/sampler_class_inheritance.png" style="width: 600px; height: 360px;" /><br />
这个BaseSampler，同时也是&nbsp;GpuSampler&nbsp;的最顶级父类。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<a href="https://www.codelast.com/?p=10932" rel="noopener noreferrer" target="_blank"><span style="background-color:#ffa07a;">前面的文章</span></a>已经讲过，sampler是collector外面包装的一层，真正去做数据收集工作的是collector类。对&nbsp;CpuSampler&nbsp;来说，它对应的collector代码实现在collectors.py中，里面包含多个collector类：CpuResetCollector，CpuWaitResetCollector，CpuEvalCollector等。<br />
所以应该从两条线来分析sampler class，一条线是&nbsp;<span style="color:#0000ff;">CpuSampler</span>&rarr;<span style="color:#0000ff;">ParallelSamplerBase</span>&rarr;<span style="color:#0000ff;">BaseSampler</span>，另一条线是collector class。为了不让篇幅过长，本文只分析第一条线，把collector class留到后面的文章。</p>
<p><span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;BaseSampler：一个主要用于定义各种接口的父类<br />
最顶层的父类BaseSampler主要定义了各种接口，很多函数都没有实现：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Menlo';font-size:12.0pt;">
<span style="color:#cc7832;font-weight:bold;">def </span><span style="font-weight:bold;">initialize</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>*args<span style="color:#cc7832;">, </span>**kwargs):
    <span style="color:#cc7832;font-weight:bold;">raise </span><span style="color:#8888c6;">NotImplementedError
</span>
<span style="color:#cc7832;font-weight:bold;">def </span><span style="font-weight:bold;">obtain_samples</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>itr):
    <span style="color:#cc7832;font-weight:bold;">raise </span><span style="color:#8888c6;">NotImplementedError  </span><span style="color:#808080;"># type: Samples
</span>
<span style="color:#cc7832;font-weight:bold;">def </span><span style="font-weight:bold;">evaluate_agent</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>itr):
    <span style="color:#cc7832;font-weight:bold;">raise </span><span style="color:#8888c6;">NotImplementedError
</span>
<span style="color:#cc7832;font-weight:bold;">def </span><span style="font-weight:bold;">shutdown</span>(<span style="color:#94558d;">self</span>):
    <span style="color:#cc7832;font-weight:bold;">pass</span></pre>
<p>而__init__()函数还是像<span style="background-color:#ffa07a;"><a href="https://www.codelast.com/?p=10831" rel="noopener noreferrer" target="_blank">之前见识过的套路</a></span>一样，使用save__init__args()来把可变参数保存到对象属性里：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Menlo';font-size:12.0pt;">
<span style="color:#cc7833;">save__init__args</span>(<span style="color:#8888c6;">locals</span>())</pre>
<p>其余就没啥好说的了。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;CpuSampler：主要充当一个入口<br />
CpuSampler类的代码相当少，它主要充当一个入口，而不是实现主要逻辑：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Menlo';font-size:12.0pt;">
<span style="color:#cc7832;font-weight:bold;">class </span><span style="font-weight:bold;">CpuSampler</span>(ParallelSamplerBase):

    <span style="color:#cc7832;font-weight:bold;">def </span><span style="color:#b200b2;">__init__</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>*args<span style="color:#cc7832;">, </span>CollectorCls=CpuResetCollector<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span>eval_CollectorCls=CpuEvalCollector<span style="color:#cc7832;">, </span>**kwargs):
        <span style="color:#808080;"># e.g. or use CpuWaitResetCollector, etc...
</span><span style="color:#808080;">        </span><span style="color:#8888c6;">super</span>().<span style="color:#b200b2;">__init__</span>(*args<span style="color:#cc7832;">, </span><span style="color:#aa4926;">CollectorCls</span>=CollectorCls<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span><span style="color:#aa4926;">eval_CollectorCls</span>=eval_CollectorCls<span style="color:#cc7832;">, </span>**kwargs)

    <span style="color:#cc7832;font-weight:bold;">def </span><span style="font-weight:bold;">obtain_samples</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>itr):
        <span style="color:#94558d;">self</span>.agent.<span style="color:#cc7833;">sync_shared_memory</span>()  <span style="color:#808080;"># New weights in workers, if needed.
</span><span style="color:#808080;">        </span><span style="color:#cc7832;font-weight:bold;">return </span><span style="color:#8888c6;">super</span>().<span style="color:#cc7833;">obtain_samples</span>(itr)

    <span style="color:#cc7832;font-weight:bold;">def </span><span style="font-weight:bold;">evaluate_agent</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>itr):
        <span style="color:#94558d;">self</span>.agent.<span style="color:#cc7833;">sync_shared_memory</span>()
        <span style="color:#cc7832;font-weight:bold;">return </span><span style="color:#8888c6;">super</span>().<span style="color:#cc7833;">evaluate_agent</span>(itr)</pre>
<p>其中，obtain_samples() 用于采样一批数据，evaluate_agent() 用于评估agent&mdash;&mdash;或者说是评估模型，差不多的意思。<br />
这两个函数都调用父类<span style="color:#0000ff;">ParallelSamplerBase</span>的同名函数来实现对应功能，后面会在其他文章里具体分析。<br />
在这两个函数的开头，都有一个&nbsp;self.agent.sync_shared_memory()&nbsp;的操作，这是干嘛？<br />
其功能是：<span style="color:#b22222;">在并行模式下，采样/评估之前先同步shared model</span>。<br />
<span style="color:#0000ff;">sync_shared_memory()</span>&nbsp;函数的实现是：</p>
<section class="output_wrapper" id="output_wrapper_id" style="font-size: 16px; color: rgb(62, 62, 62); line-height: 1.6; letter-spacing: 0px; font-family: &quot;Helvetica Neue&quot;, Helvetica, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, Arial, sans-serif;">
<pre style="font-size: inherit; color: inherit; line-height: inherit; margin-top: 0px; margin-bottom: 0px; padding: 0px;">
<code class="python language-python hljs" style="margin: 0px 2px; line-height: 18px; font-size: 14px; letter-spacing: 0px; font-family: Consolas, Inconsolata, Courier, monospace; border-radius: 0px; color: rgb(169, 183, 198); background: rgb(40, 43, 46); padding: 0.5em; overflow-wrap: normal !important; word-break: normal !important; overflow: auto !important; display: -webkit-box !important;"><span class="hljs-function" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;"><span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; overflow-wrap: inherit !important; word-break: inherit !important;">def</span>&nbsp;<span class="hljs-title" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(165, 218, 45); word-wrap: inherit !important; word-break: inherit !important;">sync_shared_memory</span><span class="hljs-params" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(255, 152, 35); word-wrap: inherit !important; word-break: inherit !important;">(self)</span>:</span>
&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">if</span>&nbsp;self.shared_model&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">is</span>&nbsp;<span class="hljs-keyword" style="font-size: inherit; line-height: inherit; margin: 0px; padding: 0px; color: rgb(248, 35, 117); word-wrap: inherit !important; word-break: inherit !important;">not</span>&nbsp;self.model:
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.shared_model.load_state_dict(strip_ddp_state_dict(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.model.state_dict()))
</code></pre>
</section>
<p>这里的意思是：当 self.model 被训练过之后，可能已经和 self.shared_model 不是一个东西了，此时需要把 self.model 的参数copy到 self.shared_model&nbsp;里。<br />
<span style="color: rgb(0, 0, 255);">strip_ddp_state_dict()</span>函数是一个很tricky的操作，为什么从 self.model&nbsp;取出来的 state_dict&nbsp;不能直接用 load_state_dict()&nbsp;加载到 self.shared_model&nbsp;里呢？关于这一点，我觉得代码的注释里写得比较清楚，建议直接去看它。<br />
这里就产生了两个问题：<span style="color:#0000ff;">✓</span> <span style="color:#ff0000;">什么是shared model？</span>&nbsp;<span style="color:#0000ff;">✓</span> <span style="color:#ff0000;">为什么要同步shared model？</span><br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;什么是shared model<br />
从名字上猜测，shared model就是一个&ldquo;共享的模型&rdquo;，之所以会有&ldquo;共享&rdquo;这个概念，是因为在多个进程中都需要使用模型，所以才需要&ldquo;共享&rdquo;。<br />
<span style="color:#ff8c00;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> rlpyt在并行(<span style="color: rgb(0, 0, 255);">parallel</span>)模式下，会产生多个&ldquo;worker&rdquo;跑在多个进程里，这些worker会各自在environment中采样，采样得到的数据用于优化模型。<br />
<span style="color: rgb(255, 140, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;worker在采样的时候会选择action，此时会用模型来做action selection。<br />
<span style="color: rgb(255, 140, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;所有worker关联到同一个agent对象(agent包含了策略网络的参数)，只有一个进程会去做优化模型(也就是反向传播之类)的工作，这一点要特别注意，是一个进程，而不是所有worker进程！<br />
<span style="color: rgb(255, 140, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2714.png" alt="✔" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span>&nbsp;在每个agent对象内部，会有一个类型为 torch.nn.Module 的 self.model 对象，还有一个 self.shared_model 对象，我们可以从agent的父类&nbsp;BaseAgent&nbsp;的__init__()函数中看到这一点：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Menlo';font-size:12.0pt;">
<span style="color:#cc7832;font-weight:bold;">def </span><span style="color:#b200b2;">__init__</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>ModelCls=<span style="color:#cc7832;font-weight:bold;">None</span><span style="color:#cc7832;">, </span>model_kwargs=<span style="color:#cc7832;font-weight:bold;">None</span><span style="color:#cc7832;">, </span>initial_model_state_dict=<span style="color:#cc7832;font-weight:bold;">None</span>):
    <span style="color:#cc7833;">save__init__args</span>(<span style="color:#8888c6;">locals</span>())
    <span style="color:#94558d;">self</span>.model = <span style="color:#cc7832;font-weight:bold;">None  </span><span style="color:#808080;"># type: torch.nn.Module
</span><span style="color:#808080;">    </span><span style="color:#94558d;">self</span>.shared_model = <span style="color:#cc7832;font-weight:bold;">None</span></pre>
<p>在agent对象初始化的时候，即在 BaseAgent.initialize() 函数中，会把 self.shared_model&nbsp;初始化成和 self.model&nbsp;一样：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Menlo';font-size:12.0pt;">
<span style="color:#cc7832;font-weight:bold;">def </span><span style="font-weight:bold;">initialize</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>env_spaces<span style="color:#cc7832;">, </span>share_memory=<span style="color:#cc7832;font-weight:bold;">False</span><span style="color:#cc7832;">, </span>**kwargs):
    <span style="color:#629755;font-style:italic;">&quot;&quot;&quot;In this default setup, self.model is treated as the model needed
</span><span style="color:#629755;font-style:italic;">    for action selection, so it is the only one shared with workers.&quot;&quot;&quot;
</span><span style="color:#629755;font-style:italic;">    </span><span style="color:#94558d;">self</span>.env_model_kwargs = <span style="color:#94558d;">self</span>.<span style="color:#cc7833;">make_env_to_model_kwargs</span>(env_spaces)
    <span style="color:#94558d;">self</span>.model = <span style="color:#94558d;">self</span>.<span style="color:#cc7833;">ModelCls</span>(**<span style="color:#94558d;">self</span>.env_model_kwargs<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">        </span>**<span style="color:#94558d;">self</span>.model_kwargs)
    <span style="color:#cc7832;font-weight:bold;">if </span>share_memory:
        <span style="color:#94558d;">self</span>.model.<span style="color:#cc7833;">share_memory</span>()
        <span style="color:#94558d;">self</span>.shared_model = <span style="color:#94558d;">self</span>.model</pre>
<p>上面代码中的 if share_memory&nbsp;这个条件是否得到满足呢？<br />
在并行模式下，也就是从 ParallelSamplerBase._agent_init()&nbsp;函数的代码我们可以发现，agent初始化的时候 share_memory&nbsp;参数被设置成了&nbsp;True：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Menlo';font-size:12.0pt;">
agent.<span style="color:#cc7833;">initialize</span>(env.spaces<span style="color:#cc7832;">, </span><span style="color:#aa4926;">share_memory</span>=<span style="color:#cc7832;font-weight:bold;">True</span><span style="color:#cc7832;">,
</span><span style="color:#cc7832;">    </span><span style="color:#aa4926;">global_B</span>=global_B<span style="color:#cc7832;">, </span><span style="color:#aa4926;">env_ranks</span>=env_ranks)</pre>
<p>所以 if share_memory&nbsp;的条件是满足的。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
如果使用GPU训练模型，那么rlpyt会把model挪到用户指定的设备上，而shared_model需要放在CPU上(<a href="https://towardsdatascience.com/speed-up-your-algorithms-part-1-pytorch-56d8a4ae7051" rel="noopener noreferrer" target="_blank"><span style="background-color: rgb(255, 160, 122);">经查</span></a>，PyTorch的Tensor或模型参数也是可以放在GPU上共享的，但有一些容易出错、需要谨慎处理的细节，所以我猜由于这个原因，作者选择了把shared_model放在CPU上)，因此，这里创建出来了一个self.shared_model，用来防止之后self.model有可能被挪到GPU的情况发生&mdash;&mdash;如果发生了，self.shared_model这个放在CPU上的模型才是多个进程间的共享模型。<br />
那么这个shared_model在CpuSampler中真的有用吗？下面我们就一层层地挖下去，看看这个东西到底有没有用。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;为什么要同步shared model<br />
先说结论：在CpuSampler里，完全不需要同步。<br />
为了确认这个结论，我们看看在使用CPU sampler的时候，BaseAgent类里的 self.shared_model&nbsp;到底用在了什么地方。通过搜索代码，发现除了 <span style="color:#0000ff;">sync_shared_memory()</span>&nbsp;函数之外，只有两个地方在用：<br />
1、上面提到的&nbsp;BaseAgent.initialize()&nbsp;函数。在这里，对 self.shared_model&nbsp;只有赋值操作，没有使用。<br />
2、to_device()&nbsp;函数：</p>
<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'Menlo';font-size:12.0pt;">
<span style="color:#cc7832;font-weight:bold;">def </span><span style="font-weight:bold;">to_device</span>(<span style="color:#94558d;">self</span><span style="color:#cc7832;">, </span>cuda_idx=<span style="color:#cc7832;font-weight:bold;">None</span>):
<span style="color:#629755;font-style:italic;">    </span><span style="color:#cc7832;font-weight:bold;">if </span>cuda_idx <span style="color:#cc7832;font-weight:bold;">is None</span>:
        <span style="color:#cc7832;font-weight:bold;">return
</span><span style="color:#cc7832;font-weight:bold;">    if </span><span style="color:#94558d;">self</span>.shared_model <span style="color:#cc7832;font-weight:bold;">is not None</span>:
        <span style="color:#94558d;">self</span>.model = <span style="color:#94558d;">self</span>.<span style="color:#cc7833;">ModelCls</span>(**<span style="color:#94558d;">self</span>.env_model_kwargs<span style="color:#cc7832;">,
</span><span style="color:#cc7832;">            </span>**<span style="color:#94558d;">self</span>.model_kwargs)
        <span style="color:#94558d;">self</span>.model.<span style="color:#cc7833;">load_state_dict</span>(<span style="color:#94558d;">self</span>.shared_model.<span style="color:#cc7833;">state_dict</span>())
    <span style="color:#94558d;">self</span>.device = torch.<span style="color:#cc7833;">device</span>(<span style="color:#008080;">&quot;cuda&quot;</span><span style="color:#cc7832;">, </span><span style="color:#aa4926;">index</span>=cuda_idx)
    <span style="color:#94558d;">self</span>.model.<span style="color:#cc7833;">to</span>(<span style="color:#94558d;">self</span>.device)</pre>
<p>在这一段代码中，当使用CPU sampler时，cuda_idx&nbsp;为 None，因此直接return了，self.shared_model&nbsp;根本触达不到。<br />
此外，BaseAgent的其他所有使用 self.shared_model&nbsp;的地方，都是和异步(<span style="color: rgb(0, 0, 255);">async_</span>)模式相关的，和并行(<span style="color:#0000ff;">parallel</span>)模式无关。<br />
因此，对CpuSampler来说，shared_model没用，不需要调用 sync_shared_memory()&nbsp;来同步shared_model。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(0, 0, 255);"><span style="background-color: rgb(0, 255, 0);"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/25b6.png" alt="▶" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span></span>&nbsp;shared model在什么情况下有意义<br />
对CpuSampler来说，BaseAgent里的 self.model&nbsp;对各个采样的worker来说都会实时更新，在action&nbsp;selection的时候使用的也是 self.model，而不是 self.shared_model，所以 shared_model&nbsp;对CpuSampler来说其实没有意义。<br />
但在其他模式下 shared model 还是有意义的，而且机制更复杂。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
这一节就到这，且听下回分解。<br />
<span style="color: rgb(255, 255, 255);">文章来源：</span><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><span style="color: rgb(255, 255, 255);">https://www.codelast.com/</span></a><br />
<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;版权声明&nbsp;<span style="color: rgb(255, 0, 0);">➤➤</span>&nbsp;<br />
转载需注明出处：<u><a href="https://www.codelast.com/" rel="noopener noreferrer" target="_blank"><em><span style="color: rgb(0, 0, 255);"><strong style="font-size: 16px;"><span style="font-family: arial, helvetica, sans-serif;">codelast.com</span></strong></span></em></a></u>&nbsp;<br />
感谢关注我的微信公众号（微信扫一扫）：</p>
<p style="border: 0px; font-size: 13px; margin: 0px 0px 9px; outline: 0px; padding: 0px; color: rgb(77, 77, 77);">
	<img decoding="async" alt="wechat qrcode of codelast" src="https://www.codelast.com/codelast_wechat_qr_code.jpg" style="width: 200px; height: 200px;" /></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.codelast.com/%e5%8e%9f%e5%88%9b-%e5%bc%ba%e5%8c%96%e5%ad%a6%e4%b9%a0%e6%a1%86%e6%9e%b6-rlpyt-%e6%ba%90%e7%a0%81%e5%88%86%e6%9e%90%ef%bc%9a8-%e5%9f%ba%e4%ba%8ecpu%e7%9a%84%e5%b9%b6%e8%a1%8c%e9%87%87%e6%a0%b7/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
